@warptoad/skinny-fat-imt-js 0.0.5 → 0.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/CREATE2.md +218 -0
  2. package/README.md +47 -3
  3. package/create2-artifacts/FatIMTPoseidon2Read.create2.json +268 -0
  4. package/create2-artifacts/FatIMTPoseidon2WriteEvent.create2.json +320 -0
  5. package/create2-artifacts/FatIMTPoseidon2WriteStorage.create2.json +320 -0
  6. package/create2-artifacts/SkinnyIMTPoseidon2Read.create2.json +258 -0
  7. package/create2-artifacts/SkinnyIMTPoseidon2WriteEvent.create2.json +301 -0
  8. package/create2-artifacts/SkinnyIMTPoseidon2WriteStorage.create2.json +301 -0
  9. package/create2-artifacts/create2-salts.json +26 -0
  10. package/dist/Trees.d.ts +4 -67
  11. package/dist/Trees.d.ts.map +1 -1
  12. package/dist/Trees.js +4 -10
  13. package/dist/Trees.js.map +1 -1
  14. package/dist/abis.js +1 -1
  15. package/dist/abis.js.map +1 -1
  16. package/dist/create2/create2.d.ts +144 -0
  17. package/dist/create2/create2.d.ts.map +1 -0
  18. package/dist/create2/create2.js +436 -0
  19. package/dist/create2/create2.js.map +1 -0
  20. package/dist/create2/index.d.ts +4 -0
  21. package/dist/create2/index.d.ts.map +1 -0
  22. package/dist/create2/index.js +4 -0
  23. package/dist/create2/index.js.map +1 -0
  24. package/dist/create2/interfaces.d.ts +79 -0
  25. package/dist/create2/interfaces.d.ts.map +1 -0
  26. package/dist/create2/interfaces.js +6 -0
  27. package/dist/create2/interfaces.js.map +1 -0
  28. package/dist/create2/types.d.ts +73 -0
  29. package/dist/create2/types.d.ts.map +1 -0
  30. package/dist/create2/types.js +4 -0
  31. package/dist/create2/types.js.map +1 -0
  32. package/dist/index.d.ts +1 -0
  33. package/dist/index.d.ts.map +1 -1
  34. package/dist/index.js +1 -0
  35. package/dist/index.js.map +1 -1
  36. package/dist/types.d.ts +71 -0
  37. package/dist/types.d.ts.map +1 -0
  38. package/dist/types.js +12 -0
  39. package/dist/types.js.map +1 -0
  40. package/package.json +10 -2
  41. package/src/Trees.ts +20 -64
  42. package/src/abis.ts +1 -1
  43. package/src/create2/create2.ts +643 -0
  44. package/src/create2/index.ts +3 -0
  45. package/src/create2/interfaces.ts +69 -0
  46. package/src/create2/types.ts +88 -0
  47. package/src/index.ts +1 -0
  48. package/src/types.ts +71 -0
@@ -0,0 +1,258 @@
1
+ {
2
+ "contractName": "SkinnyIMTPoseidon2Read",
3
+ "sourceName": "@warptoad/skinny-imt.sol/poseidon2/SkinnyIMTPoseidon2Read.sol",
4
+ "contractIdentifier": "npm/@warptoad/skinny-imt.sol@0.0.11/poseidon2/SkinnyIMTPoseidon2Read.sol:SkinnyIMTPoseidon2Read",
5
+ "compilerVersion": "0.8.28+commit.7893614a",
6
+ "evmVersion": "cancun",
7
+ "constructorArgs": "0x",
8
+ "initCode": "0x614ccb610034600b8282823980515f1a607314602857634e487b7160e01b5f525f60045260245ffd5b305f52607381538281f3fe7300000000000000000000000000000000000000003014608060405260043610610079575f3560e01c80637ff17a72116100585780637ff17a72146100c9578063c64be6ed146100ec578063dde40cba146100ff575f5ffd5b8062f306811461007d5780630145eda2146100a35780635899a5ff146100b6575b5f5ffd5b61009061008b3660046148e9565b610112565b6040519081526020015b60405180910390f35b6100906100b13660046149ad565b61012a565b6100906100c4366004614a12565b610147565b6100dc6100d7366004614a29565b610151565b604051901515815260200161009a565b6100dc6100fa366004614ad1565b6101c5565b61009061010d366004614b2d565b610235565b805160208201515f9161012491610256565b92915050565b5f61013c878787878787610112610273565b979650505050505050565b5f610124826102a2565b86545f90810361018d576040517f0d30038a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f6101a889600101548a5f01548a8a8a8a8a8a6101126102bc565b90505f6101b48a6102a2565b919091149998505050505050505050565b84545f908103610201576040517f0d30038a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f61021a8760010154885f015488888888610112610273565b90505f610226886102a2565b91909114979650505050505050565b5f61024989898989898989896101126102bc565b9998505050505050505050565b5f61026c83835f680200000000000000006103b1565b9392505050565b5f61027d86613fc5565b6102878484614021565b61029688888888888888614059565b98975050505050505050565b60018101545f908152600282016020526040812054610124565b5f885f036102f6576040517f0d30038a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6103008888614021565b61030a8484614021565b6103a3888860405180608001604052808e815260200160018e61032d9190614c38565b81526020018a8a808060200260200160405190810160405280939291908181526020018383602002808284375f920191909152505050908252506040805160208a810282810182019093528a82529283019290918b918b9182918501908490808284375f92019190915250505091525085614165565b9a9950505050505050505050565b5f7f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001808606818606828606838606828401818301848501878282089050838401888482089050886004840981019250886004850982019350888482089050888383087f19b849f69450b06848da1d39bd5e4a4302bb86744edc26238b0878e269ed23e590910197507f265ddfe127dd51bd7239347b758f0a1320eb2cc7450acc1dad47f80c8dcf34d69093019550507f199750ec472f1809e0f66a545e1e51624108ac845015c2aa3dfc36bab497d8aa90910192507f157ff3fe65ac7208110f06a5f74302b14d743ea25067f0ffd032f787c7f1cdf80190508385818009945085858609945085818609945050828581820993508584850993508581850993505081858182099250858384099250858184099250508085818209915085828309915085818309915050828401818301848501878282089050838401888482089050886004840981019250886004850982019350888482089050888383087f2e49c43c4569dd9c5fd35ac45fca33f10b15c590692f8beefe18f4896ac9490290910197507f0e35fb89981890520d4aef2b6d6506c3cb2f0b6973c24fa82731345ffa2d1f1e9093019550507f251ad47cb15c4f1105f109ae5e944f1ba9d9e7806d667ffec6fe723002e0b99690910192507f13da07dc64d428369873e97160234641f8beb56fdd05e5f3563fa39d9c22df4e0190508385818009945085858609945085818609945050828581820993508584850993508581850993505081858182099250858384099250858184099250508085818209915085828309915085818309915050828401818301848501878282089050838401888482089050886004840981019250886004850982019350888482089050888383087f0c009b84e650e6d23dc00c7dccef7483a553939689d350cd46e7b89055fd473890910197507f011f16b1c63a854f01992e3956f42d8b04eb650c6d535eb0203dec74befdca069093019550507f0ed69e5e383a688f209d9a561daa79612f3f78d0467ad45485df07093f36754990910192507f04dba94a7b0ce9e221acad41472b6bbe3aec507f5eb3d33f463672264c9f789b0190508385818009945085858609945085818609945050828581820993508584850993508581850993505081858182099250858384099250858184099250508085818209915085828309915085818309915050828401818301848501878282089050838401888482089050886004840981019250886004850982019350888482089050888383087f0a3f2637d840f3a16eb094271c9d237b6036757d4bb50bf7ce732ff1d4fa28e890910197507f259a666f129eea198f8a1c502fdb38fa39b1f075569564b6e54a485d1182323f9093019550507f28bf7459c9b2f4c6d8e7d06a4ee3a47f7745d4271038e5157a32fdf7ede0d6a190910192507f0a1ca941f057037526ea200f489be8d4c37c85bbcce6a2aeec91bd694143244701905083858180099450858586099450858186099450508285818209935085848509935085818509935050818581820992508583840992508581840992505080858182099150858283099150858183099150508284018183018485018782820890508384018884820890508860048409925088818408925088600485099350888285089350888482089050888383087f0c6f8f958be0e93053d7fd4fc54512855535ed1539f051dcb43a26fd926361cf909101975092955091935091508490508581800994508585860994508581860994505082840182018582820890508581877f10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e788090894508581877f0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b87090893508581877e544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac1586090892508581877f222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b8509089150507f123106a93cd17578d426e8128ac9d90aa9e8a00708e296e084dd57e69caaf81184019350838581820994508585860994508581860994505082840182018582820890508581877f10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e788090894508581877f0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b87090893508581877e544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac1586090892508581877f222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b8509089150507f26e1ba52ad9285d97dd3ab52f8e840085e8fa83ff1e8f1877b074867cd2dee7584019350838581820994508585860994508581860994505082840182018582820890508581877f10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e788090894508581877f0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b87090893508581877e544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac1586090892508581877f222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b8509089150507f1cb55cad7bd133de18a64c5c47b9c97cbe4d8b7bf9e095864471537e6a4ae2c584019350838581820994508585860994508581860994505082840182018582820890508581877f10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e788090894508581877f0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b87090893508581877e544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac1586090892508581877f222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b8509089150507f1dcd73e46acd8f8e0e2c7ce04bde7f6d2a53043d5060a41c7143f08e6e9055d084019350838581820994508585860994508581860994505082840182018582820890508581877f10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e788090894508581877f0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b87090893508581877e544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac1586090892508581877f222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b8509089150507f011003e32f6d9c66f5852f05474a4def0cda294a0eb4e9b9b12b9bb4512e557484019350838581820994508585860994508581860994505082840182018582820890508581877f10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e788090894508581877f0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b87090893508581877e544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac1586090892508581877f222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b8509089150507f2b1e809ac1d10ab29ad5f20d03a57dfebadfe5903f58bafed7c508dd2287ae8c84019350838581820994508585860994508581860994505082840182018582820890508581877f10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e788090894508581877f0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b87090893508581877e544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac1586090892508581877f222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b8509089150507f2539de1785b735999fb4dac35ee17ed0ef995d05ab2fc5faeaa69ae87bcec0a584019350838581820994508585860994508581860994505082840182018582820890508581877f10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e788090894508581877f0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b87090893508581877e544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac1586090892508581877f222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b8509089150507f0c246c5a2ef8ee0126497f222b3e0a0ef4e1c3d41c86d46e43982cb11d77951d84019350838581820994508585860994508581860994505082840182018582820890508581877f10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e788090894508581877f0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b87090893508581877e544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac1586090892508581877f222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b8509089150507f192089c4974f68e95408148f7c0632edbb09e6a6ad1a1c2f3f0305f5d03b527b84019350838581820994508585860994508581860994505082840182018582820890508581877f10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e788090894508581877f0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b87090893508581877e544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac1586090892508581877f222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b8509089150507f1eae0ad8ab68b2f06a0ee36eeb0d0c058529097d91096b756d8fdc2fb5a60d8584019350838581820994508585860994508581860994505082840182018582820890508581877f10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e788090894508581877f0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b87090893508581877e544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac1586090892508581877f222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b8509089150507f179190e5d0e22179e46f8282872abc88db6e2fdc0dee99e69768bd98c5d06bfb84019350838581820994508585860994508581860994505082840182018582820890508581877f10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e788090894508581877f0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b87090893508581877e544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac1586090892508581877f222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b8509089150507f29bb9e2c9076732576e9a81c7ac4b83214528f7db00f31bf6cafe794a9b3cd1c84019350838581820994508585860994508581860994505082840182018582820890508581877f10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e788090894508581877f0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b87090893508581877e544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac1586090892508581877f222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b8509089150507f225d394e42207599403efd0c2464a90d52652645882aac35b10e590e6e691e0884019350838581820994508585860994508581860994505082840182018582820890508581877f10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e788090894508581877f0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b87090893508581877e544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac1586090892508581877f222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b8509089150507f064760623c25c8cf753d238055b444532be13557451c087de09efd454b23fd5984019350838581820994508585860994508581860994505082840182018582820890508581877f10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e788090894508581877f0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b87090893508581877e544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac1586090892508581877f222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b8509089150507f10ba3a0e01df92e87f301c4b716d8a394d67f4bf42a75c10922910a78f6b5b8784019350838581820994508585860994508581860994505082840182018582820890508581877f10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e788090894508581877f0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b87090893508581877e544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac1586090892508581877f222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b8509089150507f0e070bf53f8451b24f9c6e96b0c2a801cb511bc0c242eb9d361b77693f21471c84019350838581820994508585860994508581860994505082840182018582820890508581877f10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e788090894508581877f0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b87090893508581877e544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac1586090892508581877f222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b8509089150507f1b94cd61b051b04dd39755ff93821a73ccd6cb11d2491d8aa7f921014de252fb84019350838581820994508585860994508581860994505082840182018582820890508581877f10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e788090894508581877f0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b87090893508581877e544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac1586090892508581877f222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b8509089150507f1d7cb39bafb8c744e148787a2e70230f9d4e917d5713bb050487b5aa7d74070b84019350838581820994508585860994508581860994505082840182018582820890508581877f10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e788090894508581877f0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b87090893508581877e544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac1586090892508581877f222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b8509089150507f2ec93189bd1ab4f69117d0fe980c80ff8785c2961829f701bb74ac1f303b17db84019350838581820994508585860994508581860994505082840182018582820890508581877f10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e788090894508581877f0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b87090893508581877e544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac1586090892508581877f222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b8509089150507f2db366bfdd36d277a692bb825b86275beac404a19ae07a9082ea46bd8351792684019350838581820994508585860994508581860994505082840182018582820890508581877f10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e788090894508581877f0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b87090893508581877e544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac1586090892508581877f222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b8509089150507f062100eb485db06269655cf186a68532985275428450359adc99cec6960711b884019350838581820994508585860994508581860994505082840182018582820890508581877f10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e788090894508581877f0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b87090893508581877e544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac1586090892508581877f222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b8509089150507f0761d33c66614aaa570e7f1e8244ca1120243f92fa59e4f900c567bf41f5a59b84019350838581820994508585860994508581860994505082840182018582820890508581877f10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e788090894508581877f0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b87090893508581877e544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac1586090892508581877f222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b8509089150507f20fc411a114d13992c2705aa034e3f315d78608a0f7de4ccf7a72e494855ad0d84019350838581820994508585860994508581860994505082840182018582820890508581877f10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e788090894508581877f0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b87090893508581877e544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac1586090892508581877f222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b8509089150507f25b5c004a4bdfcb5add9ec4e9ab219ba102c67e8b3effb5fc3a30f317250bc5a84019350838581820994508585860994508581860994505082840182018582820890508581877f10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e788090894508581877f0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b87090893508581877e544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac1586090892508581877f222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b8509089150507f23b1822d278ed632a494e58f6df6f5ed038b186d8474155ad87e7dff62b37f4b84019350838581820994508585860994508581860994505082840182018582820890508581877f10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e788090894508581877f0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b87090893508581877e544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac1586090892508581877f222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b8509089150507f22734b4c5c3f9493606c4ba9012499bf0f14d13bfcfcccaa16102a29cc2f69e084019350838581820994508585860994508581860994505082840182018582820890508581877f10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e788090894508581877f0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b87090893508581877e544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac1586090892508581877f222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b8509089150507f26c0c8fe09eb30b7e27a74dc33492347e5bdff409aa3610254413d3fad795ce584019350838581820994508585860994508581860994505082840182018582820890508581877f10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e788090894508581877f0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b87090893508581877e544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac1586090892508581877f222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b8509089150507f070dd0ccb6bd7bbae88eac03fa1fbb26196be3083a809829bbd626df348ccad984019350838581820994508585860994508581860994505082840182018582820890508581877f10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e788090894508581877f0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b87090893508581877e544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac1586090892508581877f222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b8509089150507f12b6595bdb329b6fb043ba78bb28c3bec2c0a6de46d8c5ad6067c4ebfd4250da84019350838581820994508585860994508581860994505082840182018582820890508581877f10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e788090894508581877f0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b87090893508581877e544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac1586090892508581877f222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b8509089150507f248d97d7f76283d63bec30e7a5876c11c06fca9b275c671c5e33d95bb7e8d72984019350838581820994508585860994508581860994505082840182018582820890508581877f10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e788090894508581877f0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b87090893508581877e544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac1586090892508581877f222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b8509089150507f1a306d439d463b0816fc6fd64cc939318b45eb759ddde4aa106d15d9bd9baaaa84019350838581820994508585860994508581860994505082840182018582820890508581877f10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e788090894508581877f0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b87090893508581877e544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac1586090892508581877f222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b8509089150507f28a8f8372e3c38daced7c00421cb4621f4f1b54ddc27821b0d62d3d6ec7c56cf84019350838581820994508585860994508581860994505082840182018582820890508581877f10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e788090894508581877f0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b87090893508581877e544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac1586090892508581877f222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b8509089150507e94975717f9a8a8bb35152f24d43294071ce320c829f388bc852183e1e2ce7e84019350838581820994508585860994508581860994505082840182018582820890508581877f10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e788090894508581877f0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b87090893508581877e544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac1586090892508581877f222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b8509089150507f04d5ee4c3aa78f7d80fde60d716480d3593f74d4f653ae83f4103246db2e8d6584019350838581820994508585860994508581860994505082840182018582820890508581877f10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e788090894508581877f0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b87090893508581877e544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac1586090892508581877f222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b8509089150507f2a6cf5e9aa03d4336349ad6fb8ed2269c7bef54b8822cc76d08495c12efde18784019350838581820994508585860994508581860994505082840182018582820890508581877f10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e788090894508581877f0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b87090893508581877e544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac1586090892508581877f222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b8509089150507f2304d31eaab960ba9274da43e19ddeb7f792180808fd6e43baae48d7efcba3f384019350838581820994508585860994508581860994505082840182018582820890508581877f10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e788090894508581877f0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b87090893508581877e544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac1586090892508581877f222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b8509089150507f03fd9ac865a4b2a6d5e7009785817249bff08a7e0726fcb4e1c11d39d199f0b084019350838581820994508585860994508581860994505082840182018582820890508581877f10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e788090894508581877f0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b87090893508581877e544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac1586090892508581877f222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b8509089150507eb7258ded52bbda2248404d55ee5044798afc3a209193073f7954d4d63b0b6484019350838581820994508585860994508581860994505082840182018582820890508581877f10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e788090894508581877f0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b87090893508581877e544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac1586090892508581877f222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b8509089150507f159f81ada0771799ec38fca2d4bf65ebb13d3a74f3298db36272c5ca65e92d9a84019350838581820994508585860994508581860994505082840182018582820890508581877f10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e788090894508581877f0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b87090893508581877e544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac1586090892508581877f222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b8509089150507f1ef90e67437fbc8550237a75bc28e3bb9000130ea25f0c5471e144cf4264431f84019350838581820994508585860994508581860994505082840182018582820890508581877f10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e788090894508581877f0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b87090893508581877e544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac1586090892508581877f222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b8509089150507f1e65f838515e5ff0196b49aa41a2d2568df739bc176b08ec95a79ed82932e30d84019350838581820994508585860994508581860994505082840182018582820890508581877f10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e788090894508581877f0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b87090893508581877e544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac1586090892508581877f222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b8509089150507f2b1b045def3a166cec6ce768d079ba74b18c844e570e1f826575c1068c94c33f84019350838581820994508585860994508581860994505082840182018582820890508581877f10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e788090894508581877f0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b87090893508581877e544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac1586090892508581877f222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b8509089150507f0832e5753ceb0ff6402543b1109229c165dc2d73bef715e3f1c6e07c168bb17384019350838581820994508585860994508581860994505082840182018582820890508581877f10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e788090894508581877f0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b87090893508581877e544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac1586090892508581877f222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b8509089150507f02f614e9cedfb3dc6b762ae0a37d41bab1b841c2e8b6451bc5a8e3c390b6ad1684019350838581820994508585860994508581860994505082840182018582820890508581877f10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e788090894508581877f0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b87090893508581877e544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac1586090892508581877f222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b8509089150507f0e2427d38bd46a60dd640b8e362cad967370ebb777bedff40f6a0be27e7ed70584019350838581820994508585860994508581860994505082840182018582820890508581877f10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e788090894508581877f0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b87090893508581877e544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac1586090892508581877f222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b8509089150507f0493630b7c670b6deb7c84d414e7ce79049f0ec098c3c7c50768bbe29214a53a84019350838581820994508585860994508581860994505082840182018582820890508581877f10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e788090894508581877f0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b87090893508581877e544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac1586090892508581877f222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b8509089150507f22ead100e8e482674decdab17066c5a26bb1515355d5461a3dc06cc85327cea984019350838581820994508585860994508581860994505082840182018582820890508581877f10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e788090894508581877f0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b87090893508581877e544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac1586090892508581877f222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b8509089150507f25b3e56e655b42cdaae2626ed2554d48583f1ae35626d04de5084e0b6d2a6f1684019350838581820994508585860994508581860994505082840182018582820890508581877f10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e788090894508581877f0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b87090893508581877e544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac1586090892508581877f222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b8509089150507f1e32752ada8836ef5837a6cde8ff13dbb599c336349e4c584b4fdc0a0cf6f9d084019350838581820994508585860994508581860994505082840182018582820890508581877f10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e788090894508581877f0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b87090893508581877e544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac1586090892508581877f222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b8509089150507f2fa2a871c15a387cc50f68f6f3c3455b23c00995f05078f672a9864074d412e584019350838581820994508585860994508581860994505082840182018582820890508581877f10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e788090894508581877f0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b87090893508581877e544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac1586090892508581877f222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b8509089150507f2f569b8a9a4424c9278e1db7311e889f54ccbf10661bab7fcd18e7c7a7d8350584019350838581820994508585860994508581860994505082840182018582820890508581877f10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e788090894508581877f0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b87090893508581877e544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac1586090892508581877f222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b8509089150507f044cb455110a8fdd531ade530234c518a7df93f7332ffd2144165374b246b43d84019350838581820994508585860994508581860994505082840182018582820890508581877f10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e788090894508581877f0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b87090893508581877e544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac1586090892508581877f222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b8509089150507f227808de93906d5d420246157f2e42b191fe8c90adfe118178ddc723a531902584019350838581820994508585860994508581860994505082840182018582820890508581877f10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e788090894508581877f0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b87090893508581877e544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac1586090892508581877f222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b8509089150507f02fcca2934e046bc623adead873579865d03781ae090ad4a8579d2e7a680035584019350838581820994508585860994508581860994505082840182018582820890508581877f10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e788090894508581877f0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b87090893508581877e544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac1586090892508581877f222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b8509089150507f0ef915f0ac120b876abccceb344a1d36bad3f3c5ab91a8ddcbec2e060d8befac84019350838581820994508585860994508581860994505082840182018582820890508581877f10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e788090894508581877f0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b87090893508581877e544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac1586090892508581877f222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b8509089150507f1797130f4b7a3e1777eb757bc6f287f6ab0fb85f6be63b09f3b16ef2b1405d38840193507f0a76225dc04170ae3306c85abab59e608c7f497c20156d4d36c668555decc6e5830192507f1fffb9ec1992d66ba1e77a7b93209af6f8fa76d48acb664796174b5326a31a5c820191507f25721c4fc15a3f2853b57c338fa538d85f8fbba6c6b9c6090611889b797b9c5f810190508385818209945085858609945085818609945050828581820993508584850993508581850993505081858182099250858384099250858184099250508085818209915085828309915085818309915050828401818301848501878282089050838401888482089050886004840981019250886004850982019350888482089050888383087f0c817fd42d5f7a41215e3d07ba197216adb4c3790705da95eb63b982bfcaf75a90910197507f13abe3f5239915d39f7e13c2c24970b6df8cf86ce00a22002bc15866e52b5a969093019550507f2106feea546224ea12ef7f39987a46c85c1bc3dc29bdbd7a92cd60acb4d391ce90910192507f21ca859468a746b6aaa79474a37dab49f1ca5a28c748bc7157e1b3345bb0f9590190508385818009945085858609945085818609945050828581820993508584850993508581850993505081858182099250858384099250858184099250508085818209915085828309915085818309915050828401818301848501878282089050838401888482089050886004840981019250886004850982019350888482089050888383087f05ccd6255c1e6f0c5cf1f0df934194c62911d14d0321662a8f1a48999e34185b90910197507f0f0e34a64b70a626e464d846674c4c8816c4fb267fe44fe6ea28678cb09490a49093019550507f0558531a4e25470c6157794ca36d0e9647dbfcfe350d64838f5b1a8a2de0d4bf90910192507f09d3dca9173ed2faceea125157683d18924cadad3f655a60b72f5864961f14550190508385818009945085858609945085818609945050828581820993508584850993508581850993505081858182099250858384099250858184099250508085818209915085828309915085818309915050828401818301848501878282089050838401888482089050886004840981019250886004850982019350888482089050888383087f0328cbd54e8c0913493f866ed03d218bf23f92d68aaec48617d4c722e5bd433590910197507f2bf07216e2aff0a223a487b1a7094e07e79e7bcc9798c648ee3347dd5329d34b9093019550507f1daf345a58006b736499c583cb76c316d6f78ed6a6dffc82111e11a63fe412df90910192507f176563472456aaa746b694c60e1823611ef39039b2edc7ff391e6f2293d2c4040190508385818009945085858609945085818609945050828581820993508584850993508581850993505081858182099250858384099250858184099250508085818209915085828309915085818309915050828401818301848501878282089050838401888482089050886004840981019250886004850982019350888482089e9d5050505050505050505050505050565b7f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001811061401e576040517fc380a82e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50565b5f5b818110156140545761404c83838381811061404057614040614bde565b90506020020135613fc5565b600101614023565b505050565b5f865f03614093576040517f0d30038a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f61409f600189614c38565b90505f87815b8b811015614156578089901c600116600103614101576140f460405180604001604052808a8a878181106140db576140db614bde565b905060200201358152602001848152508763ffffffff16565b915082600101925061414e565b88811c84821c1461414e5761414560405180604001604052808481526020018a8a8781811061413257614132614bde565b905060200201358152508763ffffffff16565b91508260010192505b6001016140a5565b509a9950505050505050505050565b5f8380158061417957508360400151518114155b156141b0576040517f470a423d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f60405180604001604052808367ffffffffffffffff8111156141d5576141d56148bc565b6040519080825280602002602001820160405280156141fe578160200160208202803683370190505b5081526020018367ffffffffffffffff81111561421d5761421d6148bc565b604051908082528060200260200182016040528015614246578160200160208202803683370190505b5090526040805160e0810182525f80825260208083018290529282018190529188015160608201526080810182905260a0810182905260c081018290529192505b83811015614310578888828181106142a1576142a1614bde565b90506020020135835f015182815181106142bd576142bd614bde565b602002602001018181525050866040015181815181106142df576142df614bde565b6020026020010151836020015182815181106142fd576142fd614bde565b6020908102919091010152600101614287565b508281525f5b865181101561433f5760808201819052614332878484896143a9565b9093509150600101614316565b50856060015151816040015114614382576040517f470a423d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b815180515f9061439457614394614bde565b60200260200101519350505050949350505050565b60408051808201909152606080825260208201526143f86040518060e001604052805f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f151581525090565b5f8660200151600161440a9190614c4b565b90505f856080015182901c600116600114614445577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff614459565b6001866080015183901c6144599190614c38565b5f60c088018190529091505b865181101561489957818860200151828151811061448557614485614bde565b6020026020010151036144be5787518051829081106144a6576144a6614bde565b602090810291909101015160a0880152600160c08801525b876020015181815181106144d4576144d4614bde565b60200260200101516001166001036145ce5761454460405180604001604052808b606001518a604001518151811061450e5761450e614bde565b602002602001015181526020018a5f0151848151811061453057614530614bde565b60200260200101518152508763ffffffff16565b885160208901518151811061455b5761455b614bde565b60200260200101818152505060018860200151828151811061457f5761457f614bde565b6020026020010151901c88602001518860200151815181106145a3576145a3614bde565b6020908102919091018101919091528701805160019081019091526040880180519091019052614887565b8660600151886020015182815181106145e9576145e9614bde565b6020026020010151146147eb578651614603826001614c4b565b10801561465f57508760200151818151811061462157614621614bde565b602002602001015160016146359190614c4b565b6020890151614645836001614c4b565b8151811061465557614655614bde565b6020026020010151145b15614727576146b560405180604001604052808a5f0151848151811061468757614687614bde565b602002602001015181526020018a5f01518460016146a59190614c4b565b8151811061453057614530614bde565b88516020890151815181106146cc576146cc614bde565b6020026020010181815250506001886020015182815181106146f0576146f0614bde565b6020026020010151901c886020015188602001518151811061471457614714614bde565b6020908102919091010152600101614875565b61477160405180604001604052808a5f0151848151811061474a5761474a614bde565b602002602001015181526020018b606001518a604001518151811061453057614530614bde565b885160208901518151811061478857614788614bde565b6020026020010181815250506001886020015182815181106147ac576147ac614bde565b6020026020010151901c88602001518860200151815181106147d0576147d0614bde565b60209081029190910101526040870180516001019052614875565b87518051829081106147ff576147ff614bde565b6020026020010151885f015188602001518151811061482057614820614bde565b60200260200101818152505060018860200151828151811061484457614844614bde565b6020026020010151901c886020015188602001518151811061486857614868614bde565b6020026020010181815250505b86602001805161488490614c5e565b90525b8061489181614c5e565b915050614465565b5050505060608301805160011c9052505060208101805182525f90529092909150565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b5f604082840312156148f9575f5ffd5b82601f830112614907575f5ffd5b6040516040810181811067ffffffffffffffff8211171561492a5761492a6148bc565b8060405250806040840185811115614940575f5ffd5b845b8181101561495a578035835260209283019201614942565b509195945050505050565b5f5f83601f840112614975575f5ffd5b50813567ffffffffffffffff81111561498c575f5ffd5b6020830191508360208260051b85010111156149a6575f5ffd5b9250929050565b5f5f5f5f5f5f60a087890312156149c2575f5ffd5b86359550602087013594506040870135935060608701359250608087013567ffffffffffffffff8111156149f4575f5ffd5b614a0089828a01614965565b979a9699509497509295939492505050565b5f60208284031215614a22575f5ffd5b5035919050565b5f5f5f5f5f5f5f6080888a031215614a3f575f5ffd5b87359650602088013567ffffffffffffffff811115614a5c575f5ffd5b614a688a828b01614965565b909750955050604088013567ffffffffffffffff811115614a87575f5ffd5b614a938a828b01614965565b909550935050606088013567ffffffffffffffff811115614ab2575f5ffd5b614abe8a828b01614965565b989b979a50959850939692959293505050565b5f5f5f5f5f60808688031215614ae5575f5ffd5b853594506020860135935060408601359250606086013567ffffffffffffffff811115614b10575f5ffd5b614b1c88828901614965565b969995985093965092949392505050565b5f5f5f5f5f5f5f5f60a0898b031215614b44575f5ffd5b8835975060208901359650604089013567ffffffffffffffff811115614b68575f5ffd5b614b748b828c01614965565b909750955050606089013567ffffffffffffffff811115614b93575f5ffd5b614b9f8b828c01614965565b909550935050608089013567ffffffffffffffff811115614bbe575f5ffd5b614bca8b828c01614965565b999c989b5096995094979396929594505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b8181038181111561012457610124614c0b565b8082018082111561012457610124614c0b565b5f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203614c8e57614c8e614c0b565b506001019056fea2646970667358221220fc44dd45aad00478284f3ea2162b77f9eede24192bafd2493142bc43c2aa4c6864736f6c634300081c0033",
9
+ "initCodeHash": "0xe86934820225b070a8ba15f98340a8e002bb7fa91c61b63f5e57b58fad823c6c",
10
+ "deployedBytecode": "0x7300000000000000000000000000000000000000003014608060405260043610610079575f3560e01c80637ff17a72116100585780637ff17a72146100c9578063c64be6ed146100ec578063dde40cba146100ff575f5ffd5b8062f306811461007d5780630145eda2146100a35780635899a5ff146100b6575b5f5ffd5b61009061008b3660046148e9565b610112565b6040519081526020015b60405180910390f35b6100906100b13660046149ad565b61012a565b6100906100c4366004614a12565b610147565b6100dc6100d7366004614a29565b610151565b604051901515815260200161009a565b6100dc6100fa366004614ad1565b6101c5565b61009061010d366004614b2d565b610235565b805160208201515f9161012491610256565b92915050565b5f61013c878787878787610112610273565b979650505050505050565b5f610124826102a2565b86545f90810361018d576040517f0d30038a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f6101a889600101548a5f01548a8a8a8a8a8a6101126102bc565b90505f6101b48a6102a2565b919091149998505050505050505050565b84545f908103610201576040517f0d30038a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f61021a8760010154885f015488888888610112610273565b90505f610226886102a2565b91909114979650505050505050565b5f61024989898989898989896101126102bc565b9998505050505050505050565b5f61026c83835f680200000000000000006103b1565b9392505050565b5f61027d86613fc5565b6102878484614021565b61029688888888888888614059565b98975050505050505050565b60018101545f908152600282016020526040812054610124565b5f885f036102f6576040517f0d30038a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6103008888614021565b61030a8484614021565b6103a3888860405180608001604052808e815260200160018e61032d9190614c38565b81526020018a8a808060200260200160405190810160405280939291908181526020018383602002808284375f920191909152505050908252506040805160208a810282810182019093528a82529283019290918b918b9182918501908490808284375f92019190915250505091525085614165565b9a9950505050505050505050565b5f7f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001808606818606828606838606828401818301848501878282089050838401888482089050886004840981019250886004850982019350888482089050888383087f19b849f69450b06848da1d39bd5e4a4302bb86744edc26238b0878e269ed23e590910197507f265ddfe127dd51bd7239347b758f0a1320eb2cc7450acc1dad47f80c8dcf34d69093019550507f199750ec472f1809e0f66a545e1e51624108ac845015c2aa3dfc36bab497d8aa90910192507f157ff3fe65ac7208110f06a5f74302b14d743ea25067f0ffd032f787c7f1cdf80190508385818009945085858609945085818609945050828581820993508584850993508581850993505081858182099250858384099250858184099250508085818209915085828309915085818309915050828401818301848501878282089050838401888482089050886004840981019250886004850982019350888482089050888383087f2e49c43c4569dd9c5fd35ac45fca33f10b15c590692f8beefe18f4896ac9490290910197507f0e35fb89981890520d4aef2b6d6506c3cb2f0b6973c24fa82731345ffa2d1f1e9093019550507f251ad47cb15c4f1105f109ae5e944f1ba9d9e7806d667ffec6fe723002e0b99690910192507f13da07dc64d428369873e97160234641f8beb56fdd05e5f3563fa39d9c22df4e0190508385818009945085858609945085818609945050828581820993508584850993508581850993505081858182099250858384099250858184099250508085818209915085828309915085818309915050828401818301848501878282089050838401888482089050886004840981019250886004850982019350888482089050888383087f0c009b84e650e6d23dc00c7dccef7483a553939689d350cd46e7b89055fd473890910197507f011f16b1c63a854f01992e3956f42d8b04eb650c6d535eb0203dec74befdca069093019550507f0ed69e5e383a688f209d9a561daa79612f3f78d0467ad45485df07093f36754990910192507f04dba94a7b0ce9e221acad41472b6bbe3aec507f5eb3d33f463672264c9f789b0190508385818009945085858609945085818609945050828581820993508584850993508581850993505081858182099250858384099250858184099250508085818209915085828309915085818309915050828401818301848501878282089050838401888482089050886004840981019250886004850982019350888482089050888383087f0a3f2637d840f3a16eb094271c9d237b6036757d4bb50bf7ce732ff1d4fa28e890910197507f259a666f129eea198f8a1c502fdb38fa39b1f075569564b6e54a485d1182323f9093019550507f28bf7459c9b2f4c6d8e7d06a4ee3a47f7745d4271038e5157a32fdf7ede0d6a190910192507f0a1ca941f057037526ea200f489be8d4c37c85bbcce6a2aeec91bd694143244701905083858180099450858586099450858186099450508285818209935085848509935085818509935050818581820992508583840992508581840992505080858182099150858283099150858183099150508284018183018485018782820890508384018884820890508860048409925088818408925088600485099350888285089350888482089050888383087f0c6f8f958be0e93053d7fd4fc54512855535ed1539f051dcb43a26fd926361cf909101975092955091935091508490508581800994508585860994508581860994505082840182018582820890508581877f10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e788090894508581877f0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b87090893508581877e544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac1586090892508581877f222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b8509089150507f123106a93cd17578d426e8128ac9d90aa9e8a00708e296e084dd57e69caaf81184019350838581820994508585860994508581860994505082840182018582820890508581877f10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e788090894508581877f0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b87090893508581877e544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac1586090892508581877f222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b8509089150507f26e1ba52ad9285d97dd3ab52f8e840085e8fa83ff1e8f1877b074867cd2dee7584019350838581820994508585860994508581860994505082840182018582820890508581877f10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e788090894508581877f0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b87090893508581877e544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac1586090892508581877f222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b8509089150507f1cb55cad7bd133de18a64c5c47b9c97cbe4d8b7bf9e095864471537e6a4ae2c584019350838581820994508585860994508581860994505082840182018582820890508581877f10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e788090894508581877f0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b87090893508581877e544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac1586090892508581877f222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b8509089150507f1dcd73e46acd8f8e0e2c7ce04bde7f6d2a53043d5060a41c7143f08e6e9055d084019350838581820994508585860994508581860994505082840182018582820890508581877f10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e788090894508581877f0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b87090893508581877e544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac1586090892508581877f222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b8509089150507f011003e32f6d9c66f5852f05474a4def0cda294a0eb4e9b9b12b9bb4512e557484019350838581820994508585860994508581860994505082840182018582820890508581877f10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e788090894508581877f0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b87090893508581877e544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac1586090892508581877f222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b8509089150507f2b1e809ac1d10ab29ad5f20d03a57dfebadfe5903f58bafed7c508dd2287ae8c84019350838581820994508585860994508581860994505082840182018582820890508581877f10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e788090894508581877f0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b87090893508581877e544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac1586090892508581877f222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b8509089150507f2539de1785b735999fb4dac35ee17ed0ef995d05ab2fc5faeaa69ae87bcec0a584019350838581820994508585860994508581860994505082840182018582820890508581877f10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e788090894508581877f0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b87090893508581877e544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac1586090892508581877f222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b8509089150507f0c246c5a2ef8ee0126497f222b3e0a0ef4e1c3d41c86d46e43982cb11d77951d84019350838581820994508585860994508581860994505082840182018582820890508581877f10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e788090894508581877f0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b87090893508581877e544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac1586090892508581877f222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b8509089150507f192089c4974f68e95408148f7c0632edbb09e6a6ad1a1c2f3f0305f5d03b527b84019350838581820994508585860994508581860994505082840182018582820890508581877f10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e788090894508581877f0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b87090893508581877e544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac1586090892508581877f222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b8509089150507f1eae0ad8ab68b2f06a0ee36eeb0d0c058529097d91096b756d8fdc2fb5a60d8584019350838581820994508585860994508581860994505082840182018582820890508581877f10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e788090894508581877f0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b87090893508581877e544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac1586090892508581877f222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b8509089150507f179190e5d0e22179e46f8282872abc88db6e2fdc0dee99e69768bd98c5d06bfb84019350838581820994508585860994508581860994505082840182018582820890508581877f10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e788090894508581877f0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b87090893508581877e544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac1586090892508581877f222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b8509089150507f29bb9e2c9076732576e9a81c7ac4b83214528f7db00f31bf6cafe794a9b3cd1c84019350838581820994508585860994508581860994505082840182018582820890508581877f10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e788090894508581877f0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b87090893508581877e544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac1586090892508581877f222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b8509089150507f225d394e42207599403efd0c2464a90d52652645882aac35b10e590e6e691e0884019350838581820994508585860994508581860994505082840182018582820890508581877f10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e788090894508581877f0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b87090893508581877e544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac1586090892508581877f222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b8509089150507f064760623c25c8cf753d238055b444532be13557451c087de09efd454b23fd5984019350838581820994508585860994508581860994505082840182018582820890508581877f10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e788090894508581877f0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b87090893508581877e544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac1586090892508581877f222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b8509089150507f10ba3a0e01df92e87f301c4b716d8a394d67f4bf42a75c10922910a78f6b5b8784019350838581820994508585860994508581860994505082840182018582820890508581877f10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e788090894508581877f0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b87090893508581877e544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac1586090892508581877f222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b8509089150507f0e070bf53f8451b24f9c6e96b0c2a801cb511bc0c242eb9d361b77693f21471c84019350838581820994508585860994508581860994505082840182018582820890508581877f10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e788090894508581877f0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b87090893508581877e544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac1586090892508581877f222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b8509089150507f1b94cd61b051b04dd39755ff93821a73ccd6cb11d2491d8aa7f921014de252fb84019350838581820994508585860994508581860994505082840182018582820890508581877f10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e788090894508581877f0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b87090893508581877e544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac1586090892508581877f222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b8509089150507f1d7cb39bafb8c744e148787a2e70230f9d4e917d5713bb050487b5aa7d74070b84019350838581820994508585860994508581860994505082840182018582820890508581877f10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e788090894508581877f0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b87090893508581877e544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac1586090892508581877f222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b8509089150507f2ec93189bd1ab4f69117d0fe980c80ff8785c2961829f701bb74ac1f303b17db84019350838581820994508585860994508581860994505082840182018582820890508581877f10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e788090894508581877f0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b87090893508581877e544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac1586090892508581877f222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b8509089150507f2db366bfdd36d277a692bb825b86275beac404a19ae07a9082ea46bd8351792684019350838581820994508585860994508581860994505082840182018582820890508581877f10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e788090894508581877f0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b87090893508581877e544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac1586090892508581877f222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b8509089150507f062100eb485db06269655cf186a68532985275428450359adc99cec6960711b884019350838581820994508585860994508581860994505082840182018582820890508581877f10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e788090894508581877f0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b87090893508581877e544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac1586090892508581877f222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b8509089150507f0761d33c66614aaa570e7f1e8244ca1120243f92fa59e4f900c567bf41f5a59b84019350838581820994508585860994508581860994505082840182018582820890508581877f10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e788090894508581877f0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b87090893508581877e544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac1586090892508581877f222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b8509089150507f20fc411a114d13992c2705aa034e3f315d78608a0f7de4ccf7a72e494855ad0d84019350838581820994508585860994508581860994505082840182018582820890508581877f10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e788090894508581877f0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b87090893508581877e544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac1586090892508581877f222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b8509089150507f25b5c004a4bdfcb5add9ec4e9ab219ba102c67e8b3effb5fc3a30f317250bc5a84019350838581820994508585860994508581860994505082840182018582820890508581877f10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e788090894508581877f0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b87090893508581877e544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac1586090892508581877f222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b8509089150507f23b1822d278ed632a494e58f6df6f5ed038b186d8474155ad87e7dff62b37f4b84019350838581820994508585860994508581860994505082840182018582820890508581877f10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e788090894508581877f0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b87090893508581877e544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac1586090892508581877f222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b8509089150507f22734b4c5c3f9493606c4ba9012499bf0f14d13bfcfcccaa16102a29cc2f69e084019350838581820994508585860994508581860994505082840182018582820890508581877f10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e788090894508581877f0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b87090893508581877e544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac1586090892508581877f222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b8509089150507f26c0c8fe09eb30b7e27a74dc33492347e5bdff409aa3610254413d3fad795ce584019350838581820994508585860994508581860994505082840182018582820890508581877f10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e788090894508581877f0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b87090893508581877e544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac1586090892508581877f222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b8509089150507f070dd0ccb6bd7bbae88eac03fa1fbb26196be3083a809829bbd626df348ccad984019350838581820994508585860994508581860994505082840182018582820890508581877f10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e788090894508581877f0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b87090893508581877e544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac1586090892508581877f222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b8509089150507f12b6595bdb329b6fb043ba78bb28c3bec2c0a6de46d8c5ad6067c4ebfd4250da84019350838581820994508585860994508581860994505082840182018582820890508581877f10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e788090894508581877f0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b87090893508581877e544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac1586090892508581877f222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b8509089150507f248d97d7f76283d63bec30e7a5876c11c06fca9b275c671c5e33d95bb7e8d72984019350838581820994508585860994508581860994505082840182018582820890508581877f10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e788090894508581877f0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b87090893508581877e544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac1586090892508581877f222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b8509089150507f1a306d439d463b0816fc6fd64cc939318b45eb759ddde4aa106d15d9bd9baaaa84019350838581820994508585860994508581860994505082840182018582820890508581877f10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e788090894508581877f0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b87090893508581877e544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac1586090892508581877f222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b8509089150507f28a8f8372e3c38daced7c00421cb4621f4f1b54ddc27821b0d62d3d6ec7c56cf84019350838581820994508585860994508581860994505082840182018582820890508581877f10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e788090894508581877f0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b87090893508581877e544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac1586090892508581877f222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b8509089150507e94975717f9a8a8bb35152f24d43294071ce320c829f388bc852183e1e2ce7e84019350838581820994508585860994508581860994505082840182018582820890508581877f10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e788090894508581877f0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b87090893508581877e544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac1586090892508581877f222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b8509089150507f04d5ee4c3aa78f7d80fde60d716480d3593f74d4f653ae83f4103246db2e8d6584019350838581820994508585860994508581860994505082840182018582820890508581877f10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e788090894508581877f0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b87090893508581877e544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac1586090892508581877f222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b8509089150507f2a6cf5e9aa03d4336349ad6fb8ed2269c7bef54b8822cc76d08495c12efde18784019350838581820994508585860994508581860994505082840182018582820890508581877f10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e788090894508581877f0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b87090893508581877e544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac1586090892508581877f222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b8509089150507f2304d31eaab960ba9274da43e19ddeb7f792180808fd6e43baae48d7efcba3f384019350838581820994508585860994508581860994505082840182018582820890508581877f10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e788090894508581877f0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b87090893508581877e544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac1586090892508581877f222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b8509089150507f03fd9ac865a4b2a6d5e7009785817249bff08a7e0726fcb4e1c11d39d199f0b084019350838581820994508585860994508581860994505082840182018582820890508581877f10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e788090894508581877f0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b87090893508581877e544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac1586090892508581877f222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b8509089150507eb7258ded52bbda2248404d55ee5044798afc3a209193073f7954d4d63b0b6484019350838581820994508585860994508581860994505082840182018582820890508581877f10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e788090894508581877f0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b87090893508581877e544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac1586090892508581877f222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b8509089150507f159f81ada0771799ec38fca2d4bf65ebb13d3a74f3298db36272c5ca65e92d9a84019350838581820994508585860994508581860994505082840182018582820890508581877f10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e788090894508581877f0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b87090893508581877e544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac1586090892508581877f222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b8509089150507f1ef90e67437fbc8550237a75bc28e3bb9000130ea25f0c5471e144cf4264431f84019350838581820994508585860994508581860994505082840182018582820890508581877f10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e788090894508581877f0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b87090893508581877e544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac1586090892508581877f222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b8509089150507f1e65f838515e5ff0196b49aa41a2d2568df739bc176b08ec95a79ed82932e30d84019350838581820994508585860994508581860994505082840182018582820890508581877f10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e788090894508581877f0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b87090893508581877e544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac1586090892508581877f222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b8509089150507f2b1b045def3a166cec6ce768d079ba74b18c844e570e1f826575c1068c94c33f84019350838581820994508585860994508581860994505082840182018582820890508581877f10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e788090894508581877f0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b87090893508581877e544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac1586090892508581877f222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b8509089150507f0832e5753ceb0ff6402543b1109229c165dc2d73bef715e3f1c6e07c168bb17384019350838581820994508585860994508581860994505082840182018582820890508581877f10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e788090894508581877f0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b87090893508581877e544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac1586090892508581877f222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b8509089150507f02f614e9cedfb3dc6b762ae0a37d41bab1b841c2e8b6451bc5a8e3c390b6ad1684019350838581820994508585860994508581860994505082840182018582820890508581877f10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e788090894508581877f0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b87090893508581877e544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac1586090892508581877f222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b8509089150507f0e2427d38bd46a60dd640b8e362cad967370ebb777bedff40f6a0be27e7ed70584019350838581820994508585860994508581860994505082840182018582820890508581877f10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e788090894508581877f0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b87090893508581877e544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac1586090892508581877f222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b8509089150507f0493630b7c670b6deb7c84d414e7ce79049f0ec098c3c7c50768bbe29214a53a84019350838581820994508585860994508581860994505082840182018582820890508581877f10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e788090894508581877f0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b87090893508581877e544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac1586090892508581877f222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b8509089150507f22ead100e8e482674decdab17066c5a26bb1515355d5461a3dc06cc85327cea984019350838581820994508585860994508581860994505082840182018582820890508581877f10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e788090894508581877f0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b87090893508581877e544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac1586090892508581877f222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b8509089150507f25b3e56e655b42cdaae2626ed2554d48583f1ae35626d04de5084e0b6d2a6f1684019350838581820994508585860994508581860994505082840182018582820890508581877f10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e788090894508581877f0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b87090893508581877e544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac1586090892508581877f222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b8509089150507f1e32752ada8836ef5837a6cde8ff13dbb599c336349e4c584b4fdc0a0cf6f9d084019350838581820994508585860994508581860994505082840182018582820890508581877f10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e788090894508581877f0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b87090893508581877e544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac1586090892508581877f222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b8509089150507f2fa2a871c15a387cc50f68f6f3c3455b23c00995f05078f672a9864074d412e584019350838581820994508585860994508581860994505082840182018582820890508581877f10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e788090894508581877f0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b87090893508581877e544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac1586090892508581877f222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b8509089150507f2f569b8a9a4424c9278e1db7311e889f54ccbf10661bab7fcd18e7c7a7d8350584019350838581820994508585860994508581860994505082840182018582820890508581877f10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e788090894508581877f0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b87090893508581877e544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac1586090892508581877f222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b8509089150507f044cb455110a8fdd531ade530234c518a7df93f7332ffd2144165374b246b43d84019350838581820994508585860994508581860994505082840182018582820890508581877f10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e788090894508581877f0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b87090893508581877e544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac1586090892508581877f222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b8509089150507f227808de93906d5d420246157f2e42b191fe8c90adfe118178ddc723a531902584019350838581820994508585860994508581860994505082840182018582820890508581877f10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e788090894508581877f0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b87090893508581877e544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac1586090892508581877f222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b8509089150507f02fcca2934e046bc623adead873579865d03781ae090ad4a8579d2e7a680035584019350838581820994508585860994508581860994505082840182018582820890508581877f10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e788090894508581877f0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b87090893508581877e544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac1586090892508581877f222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b8509089150507f0ef915f0ac120b876abccceb344a1d36bad3f3c5ab91a8ddcbec2e060d8befac84019350838581820994508585860994508581860994505082840182018582820890508581877f10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e788090894508581877f0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b87090893508581877e544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac1586090892508581877f222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b8509089150507f1797130f4b7a3e1777eb757bc6f287f6ab0fb85f6be63b09f3b16ef2b1405d38840193507f0a76225dc04170ae3306c85abab59e608c7f497c20156d4d36c668555decc6e5830192507f1fffb9ec1992d66ba1e77a7b93209af6f8fa76d48acb664796174b5326a31a5c820191507f25721c4fc15a3f2853b57c338fa538d85f8fbba6c6b9c6090611889b797b9c5f810190508385818209945085858609945085818609945050828581820993508584850993508581850993505081858182099250858384099250858184099250508085818209915085828309915085818309915050828401818301848501878282089050838401888482089050886004840981019250886004850982019350888482089050888383087f0c817fd42d5f7a41215e3d07ba197216adb4c3790705da95eb63b982bfcaf75a90910197507f13abe3f5239915d39f7e13c2c24970b6df8cf86ce00a22002bc15866e52b5a969093019550507f2106feea546224ea12ef7f39987a46c85c1bc3dc29bdbd7a92cd60acb4d391ce90910192507f21ca859468a746b6aaa79474a37dab49f1ca5a28c748bc7157e1b3345bb0f9590190508385818009945085858609945085818609945050828581820993508584850993508581850993505081858182099250858384099250858184099250508085818209915085828309915085818309915050828401818301848501878282089050838401888482089050886004840981019250886004850982019350888482089050888383087f05ccd6255c1e6f0c5cf1f0df934194c62911d14d0321662a8f1a48999e34185b90910197507f0f0e34a64b70a626e464d846674c4c8816c4fb267fe44fe6ea28678cb09490a49093019550507f0558531a4e25470c6157794ca36d0e9647dbfcfe350d64838f5b1a8a2de0d4bf90910192507f09d3dca9173ed2faceea125157683d18924cadad3f655a60b72f5864961f14550190508385818009945085858609945085818609945050828581820993508584850993508581850993505081858182099250858384099250858184099250508085818209915085828309915085818309915050828401818301848501878282089050838401888482089050886004840981019250886004850982019350888482089050888383087f0328cbd54e8c0913493f866ed03d218bf23f92d68aaec48617d4c722e5bd433590910197507f2bf07216e2aff0a223a487b1a7094e07e79e7bcc9798c648ee3347dd5329d34b9093019550507f1daf345a58006b736499c583cb76c316d6f78ed6a6dffc82111e11a63fe412df90910192507f176563472456aaa746b694c60e1823611ef39039b2edc7ff391e6f2293d2c4040190508385818009945085858609945085818609945050828581820993508584850993508581850993505081858182099250858384099250858184099250508085818209915085828309915085818309915050828401818301848501878282089050838401888482089050886004840981019250886004850982019350888482089e9d5050505050505050505050505050565b7f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001811061401e576040517fc380a82e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50565b5f5b818110156140545761404c83838381811061404057614040614bde565b90506020020135613fc5565b600101614023565b505050565b5f865f03614093576040517f0d30038a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f61409f600189614c38565b90505f87815b8b811015614156578089901c600116600103614101576140f460405180604001604052808a8a878181106140db576140db614bde565b905060200201358152602001848152508763ffffffff16565b915082600101925061414e565b88811c84821c1461414e5761414560405180604001604052808481526020018a8a8781811061413257614132614bde565b905060200201358152508763ffffffff16565b91508260010192505b6001016140a5565b509a9950505050505050505050565b5f8380158061417957508360400151518114155b156141b0576040517f470a423d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f60405180604001604052808367ffffffffffffffff8111156141d5576141d56148bc565b6040519080825280602002602001820160405280156141fe578160200160208202803683370190505b5081526020018367ffffffffffffffff81111561421d5761421d6148bc565b604051908082528060200260200182016040528015614246578160200160208202803683370190505b5090526040805160e0810182525f80825260208083018290529282018190529188015160608201526080810182905260a0810182905260c081018290529192505b83811015614310578888828181106142a1576142a1614bde565b90506020020135835f015182815181106142bd576142bd614bde565b602002602001018181525050866040015181815181106142df576142df614bde565b6020026020010151836020015182815181106142fd576142fd614bde565b6020908102919091010152600101614287565b508281525f5b865181101561433f5760808201819052614332878484896143a9565b9093509150600101614316565b50856060015151816040015114614382576040517f470a423d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b815180515f9061439457614394614bde565b60200260200101519350505050949350505050565b60408051808201909152606080825260208201526143f86040518060e001604052805f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f151581525090565b5f8660200151600161440a9190614c4b565b90505f856080015182901c600116600114614445577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff614459565b6001866080015183901c6144599190614c38565b5f60c088018190529091505b865181101561489957818860200151828151811061448557614485614bde565b6020026020010151036144be5787518051829081106144a6576144a6614bde565b602090810291909101015160a0880152600160c08801525b876020015181815181106144d4576144d4614bde565b60200260200101516001166001036145ce5761454460405180604001604052808b606001518a604001518151811061450e5761450e614bde565b602002602001015181526020018a5f0151848151811061453057614530614bde565b60200260200101518152508763ffffffff16565b885160208901518151811061455b5761455b614bde565b60200260200101818152505060018860200151828151811061457f5761457f614bde565b6020026020010151901c88602001518860200151815181106145a3576145a3614bde565b6020908102919091018101919091528701805160019081019091526040880180519091019052614887565b8660600151886020015182815181106145e9576145e9614bde565b6020026020010151146147eb578651614603826001614c4b565b10801561465f57508760200151818151811061462157614621614bde565b602002602001015160016146359190614c4b565b6020890151614645836001614c4b565b8151811061465557614655614bde565b6020026020010151145b15614727576146b560405180604001604052808a5f0151848151811061468757614687614bde565b602002602001015181526020018a5f01518460016146a59190614c4b565b8151811061453057614530614bde565b88516020890151815181106146cc576146cc614bde565b6020026020010181815250506001886020015182815181106146f0576146f0614bde565b6020026020010151901c886020015188602001518151811061471457614714614bde565b6020908102919091010152600101614875565b61477160405180604001604052808a5f0151848151811061474a5761474a614bde565b602002602001015181526020018b606001518a604001518151811061453057614530614bde565b885160208901518151811061478857614788614bde565b6020026020010181815250506001886020015182815181106147ac576147ac614bde565b6020026020010151901c88602001518860200151815181106147d0576147d0614bde565b60209081029190910101526040870180516001019052614875565b87518051829081106147ff576147ff614bde565b6020026020010151885f015188602001518151811061482057614820614bde565b60200260200101818152505060018860200151828151811061484457614844614bde565b6020026020010151901c886020015188602001518151811061486857614868614bde565b6020026020010181815250505b86602001805161488490614c5e565b90525b8061489181614c5e565b915050614465565b5050505060608301805160011c9052505060208101805182525f90529092909150565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b5f604082840312156148f9575f5ffd5b82601f830112614907575f5ffd5b6040516040810181811067ffffffffffffffff8211171561492a5761492a6148bc565b8060405250806040840185811115614940575f5ffd5b845b8181101561495a578035835260209283019201614942565b509195945050505050565b5f5f83601f840112614975575f5ffd5b50813567ffffffffffffffff81111561498c575f5ffd5b6020830191508360208260051b85010111156149a6575f5ffd5b9250929050565b5f5f5f5f5f5f60a087890312156149c2575f5ffd5b86359550602087013594506040870135935060608701359250608087013567ffffffffffffffff8111156149f4575f5ffd5b614a0089828a01614965565b979a9699509497509295939492505050565b5f60208284031215614a22575f5ffd5b5035919050565b5f5f5f5f5f5f5f6080888a031215614a3f575f5ffd5b87359650602088013567ffffffffffffffff811115614a5c575f5ffd5b614a688a828b01614965565b909750955050604088013567ffffffffffffffff811115614a87575f5ffd5b614a938a828b01614965565b909550935050606088013567ffffffffffffffff811115614ab2575f5ffd5b614abe8a828b01614965565b989b979a50959850939692959293505050565b5f5f5f5f5f60808688031215614ae5575f5ffd5b853594506020860135935060408601359250606086013567ffffffffffffffff811115614b10575f5ffd5b614b1c88828901614965565b969995985093965092949392505050565b5f5f5f5f5f5f5f5f60a0898b031215614b44575f5ffd5b8835975060208901359650604089013567ffffffffffffffff811115614b68575f5ffd5b614b748b828c01614965565b909750955050606089013567ffffffffffffffff811115614b93575f5ffd5b614b9f8b828c01614965565b909550935050608089013567ffffffffffffffff811115614bbe575f5ffd5b614bca8b828c01614965565b999c989b5096995094979396929594505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b8181038181111561012457610124614c0b565b8082018082111561012457610124614c0b565b5f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203614c8e57614c8e614c0b565b506001019056fea2646970667358221220fc44dd45aad00478284f3ea2162b77f9eede24192bafd2493142bc43c2aa4c6864736f6c634300081c0033",
11
+ "callProtectionOffset": 1,
12
+ "immutableReferences": {},
13
+ "linkedLibraries": {},
14
+ "abi": [
15
+ {
16
+ "inputs": [],
17
+ "name": "LeafGreaterThanSnarkScalarField",
18
+ "type": "error"
19
+ },
20
+ {
21
+ "inputs": [],
22
+ "name": "TreeEmpty",
23
+ "type": "error"
24
+ },
25
+ {
26
+ "inputs": [],
27
+ "name": "WrongMultiProof",
28
+ "type": "error"
29
+ },
30
+ {
31
+ "inputs": [
32
+ {
33
+ "internalType": "uint256[2]",
34
+ "name": "leaves",
35
+ "type": "uint256[2]"
36
+ }
37
+ ],
38
+ "name": "hasher",
39
+ "outputs": [
40
+ {
41
+ "internalType": "uint256",
42
+ "name": "",
43
+ "type": "uint256"
44
+ }
45
+ ],
46
+ "stateMutability": "pure",
47
+ "type": "function"
48
+ },
49
+ {
50
+ "inputs": [
51
+ {
52
+ "internalType": "uint256",
53
+ "name": "treeDepth",
54
+ "type": "uint256"
55
+ },
56
+ {
57
+ "internalType": "uint256",
58
+ "name": "treeSize",
59
+ "type": "uint256"
60
+ },
61
+ {
62
+ "internalType": "uint256[]",
63
+ "name": "leaves",
64
+ "type": "uint256[]"
65
+ },
66
+ {
67
+ "internalType": "uint256[]",
68
+ "name": "leafIndexes",
69
+ "type": "uint256[]"
70
+ },
71
+ {
72
+ "internalType": "uint256[]",
73
+ "name": "proofSiblings",
74
+ "type": "uint256[]"
75
+ }
76
+ ],
77
+ "name": "proofManyToRootBN254",
78
+ "outputs": [
79
+ {
80
+ "internalType": "uint256",
81
+ "name": "",
82
+ "type": "uint256"
83
+ }
84
+ ],
85
+ "stateMutability": "view",
86
+ "type": "function"
87
+ },
88
+ {
89
+ "inputs": [
90
+ {
91
+ "internalType": "uint256",
92
+ "name": "treeDepth",
93
+ "type": "uint256"
94
+ },
95
+ {
96
+ "internalType": "uint256",
97
+ "name": "treeSize",
98
+ "type": "uint256"
99
+ },
100
+ {
101
+ "internalType": "uint256",
102
+ "name": "leaf",
103
+ "type": "uint256"
104
+ },
105
+ {
106
+ "internalType": "uint256",
107
+ "name": "leafIndex",
108
+ "type": "uint256"
109
+ },
110
+ {
111
+ "internalType": "uint256[]",
112
+ "name": "proofSiblings",
113
+ "type": "uint256[]"
114
+ }
115
+ ],
116
+ "name": "proofToRootBN254",
117
+ "outputs": [
118
+ {
119
+ "internalType": "uint256",
120
+ "name": "",
121
+ "type": "uint256"
122
+ }
123
+ ],
124
+ "stateMutability": "view",
125
+ "type": "function"
126
+ }
127
+ ],
128
+ "solcInput": {
129
+ "language": "Solidity",
130
+ "settings": {
131
+ "evmVersion": "cancun",
132
+ "optimizer": {
133
+ "enabled": true,
134
+ "runs": 4294967295
135
+ },
136
+ "outputSelection": {
137
+ "*": {
138
+ "": [
139
+ "ast"
140
+ ],
141
+ "*": [
142
+ "abi",
143
+ "evm.bytecode.linkReferences",
144
+ "evm.bytecode.object",
145
+ "evm.bytecode.opcodes",
146
+ "evm.bytecode.sourceMap",
147
+ "evm.deployedBytecode.immutableReferences",
148
+ "evm.deployedBytecode.linkReferences",
149
+ "evm.deployedBytecode.object",
150
+ "evm.deployedBytecode.opcodes",
151
+ "evm.deployedBytecode.sourceMap",
152
+ "evm.methodIdentifiers"
153
+ ]
154
+ }
155
+ },
156
+ "remappings": [
157
+ "npm/@warptoad/fat-imt.sol@0.0.11/:@openzeppelin/contracts/=npm/@openzeppelin/contracts@5.6.1/",
158
+ "npm/@warptoad/fat-imt.sol@0.0.11/:poseidon2-evm/=npm/poseidon2-evm@2.0.0/",
159
+ "npm/@warptoad/skinny-imt.sol@0.0.11/:@openzeppelin/contracts/=npm/@openzeppelin/contracts@5.6.1/",
160
+ "npm/@warptoad/skinny-imt.sol@0.0.11/:poseidon2-evm/=npm/poseidon2-evm@2.0.0/",
161
+ "project/:@warptoad/fat-imt.sol/=npm/@warptoad/fat-imt.sol@0.0.11/",
162
+ "project/:@warptoad/skinny-imt.sol/=npm/@warptoad/skinny-imt.sol@0.0.11/"
163
+ ]
164
+ },
165
+ "sources": {
166
+ "npm/@openzeppelin/contracts@5.6.1/utils/introspection/ERC165.sol": {
167
+ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.4.0) (utils/introspection/ERC165.sol)\n\npragma solidity ^0.8.20;\n\nimport {IERC165} from \"./IERC165.sol\";\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC-165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /// @inheritdoc IERC165\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n"
168
+ },
169
+ "npm/@openzeppelin/contracts@5.6.1/utils/introspection/IERC165.sol": {
170
+ "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.4.0) (utils/introspection/IERC165.sol)\n\npragma solidity >=0.4.16;\n\n/**\n * @dev Interface of the ERC-165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[ERC].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[ERC section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n"
171
+ },
172
+ "npm/@warptoad/fat-imt.sol@0.0.11/Constants.sol": {
173
+ "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.4;\n\nuint256 constant SNARK_SCALAR_FIELD = 21888242871839275222246405745257275088548364400416034343698204186575808495617;\n"
174
+ },
175
+ "npm/@warptoad/fat-imt.sol@0.0.11/FatIMTReadableEvent.sol": {
176
+ "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.20;\n\nimport {FatIMTDataEvent, InternalFatIMTEvent, NotInitialized} from \"./InternalFatIMTEvent.sol\";\nimport {ERC165} from \"@openzeppelin/contracts/utils/introspection/ERC165.sol\";\nimport {IERC165} from \"@openzeppelin/contracts/utils/introspection/IERC165.sol\";\nimport {IFatIMTReadableEvent} from \"./interfaces/IFatIMTReadableEvent.sol\";\n\nabstract contract FatIMTReadableEvent is ERC165, IFatIMTReadableEvent {\n /// @dev Resolves `treeId` to the consumer's tree storage. Single-tree consumers may ignore `treeId`.\n function _getFatEventTree(uint256 treeId) internal view virtual returns (FatIMTDataEvent storage);\n\n function _initializedFatEventTree(uint256 treeId) internal view returns (FatIMTDataEvent storage) {\n FatIMTDataEvent storage tree = _getFatEventTree(treeId);\n if (tree.treeId == 0) {\n revert NotInitialized();\n }\n return tree;\n }\n\n /// @dev `supportsInterface` is the one name in this base that cannot carry the `Fat` prefix —\n /// ERC-165 fixes its selector — so it is the single point a consumer holding a fat tree *and* a\n /// skinny one has to reconcile, where every other name in the two families is disjoint by\n /// construction. Both families root at OpenZeppelin's `ERC165`, so that reconciliation is the\n /// usual one-liner and the `super` walk covers both:\n ///\n /// function supportsInterface(\n /// bytes4 interfaceId\n /// ) public view override(FatIMTReadableStorage, SkinnyIMTReadableStorage) returns (bool) {\n /// return super.supportsInterface(interfaceId);\n /// }\n ///\n /// A consumer of one family inherits the right answer and writes nothing at all.\n function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {\n return interfaceId == type(IFatIMTReadableEvent).interfaceId || super.supportsInterface(interfaceId);\n }\n\n function getFatLeaves(\n uint256 treeId,\n uint256 firstIndex,\n uint256 endIndex\n ) external view virtual override returns (uint256[] memory) {\n return InternalFatIMTEvent._getNodes(_initializedFatEventTree(treeId), firstIndex, endIndex, 0);\n }\n\n function getFatNodes(\n uint256 treeId,\n uint256 firstIndex,\n uint256 endIndex,\n uint256 level\n ) external view virtual override returns (uint256[] memory) {\n return InternalFatIMTEvent._getNodes(_initializedFatEventTree(treeId), firstIndex, endIndex, level);\n }\n\n function getFatRoot(uint256 treeId) external view virtual override returns (uint256) {\n return InternalFatIMTEvent._root(_initializedFatEventTree(treeId));\n }\n\n function getFatSize(uint256 treeId) external view virtual override returns (uint256) {\n return _initializedFatEventTree(treeId).size;\n }\n\n function getFatDepth(uint256 treeId) external view virtual override returns (uint256) {\n return _initializedFatEventTree(treeId).depth;\n }\n}\n"
177
+ },
178
+ "npm/@warptoad/fat-imt.sol@0.0.11/FatIMTReadableStorage.sol": {
179
+ "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.20;\n\nimport {FatIMTDataStorage, InternalFatIMTStorage} from \"./InternalFatIMTStorage.sol\";\nimport {FatIMTDataEvent, NotInitialized} from \"./InternalFatIMTEvent.sol\";\nimport {FatIMTReadableEvent} from \"./FatIMTReadableEvent.sol\";\nimport {IERC165} from \"@openzeppelin/contracts/utils/introspection/IERC165.sol\";\nimport {IFatIMTReadableEvent} from \"./interfaces/IFatIMTReadableEvent.sol\";\nimport {IFatIMTReadableStorage} from \"./interfaces/IFatIMTReadableStorage.sol\";\n\n/// @title FatIMTReadableStorage\n/// @dev\nabstract contract FatIMTReadableStorage is FatIMTReadableEvent, IFatIMTReadableStorage {\n /// @dev Resolves `treeId` to the consumer's tree storage. Single-tree consumers may ignore `treeId`.\n function _getFatStorageTree(uint256 treeId) internal view virtual returns (FatIMTDataStorage storage);\n\n /// @dev Override this if you have both a storage and a event tree\n function _getFatEventTree(uint256 treeId) internal view virtual override returns (FatIMTDataEvent storage) {\n return _getFatStorageTree(treeId).treeData;\n }\n\n /// @dev Resolves `treeId` and rejects a tree that was never initialized. A mapping always resolves\n /// — an unwritten key yields an all-zero struct — so without this a caller asking for a tree that\n /// doesn't exist would get an empty array (or a slot pointing at zeros) and read it as \"this tree\n /// is empty\". `_init` sets `treeId` to `slot + 1`, so a zero `treeId` means uninitialized.\n /// @notice Storage cannot distinguish a never-written key from one written to zero or `delete`d,\n /// so all three surface as the same error; there is no finer distinction available to detect.\n function _initializedFatStorageTree(uint256 treeId) internal view returns (FatIMTDataStorage storage) {\n FatIMTDataStorage storage tree = _getFatStorageTree(treeId);\n if (tree.treeData.treeId == 0) {\n revert NotInitialized();\n }\n return tree;\n }\n\n /// @dev Only the id this base adds; `super` walks on to `FatIMTReadableEvent` for the event id\n /// and OpenZeppelin's `ERC165` for `0x01ffc9a7`. Note this id covers *only* `getFatLeavesBaseSlot`\n /// — `getFatLeaves` is overridden below rather than added, so it stays in the event id, and\n /// inherited functions are excluded from `type(I).interfaceId` — so a client after the whole read\n /// ABI checks the event id too.\n function supportsInterface(\n bytes4 interfaceId\n ) public view virtual override(FatIMTReadableEvent, IERC165) returns (bool) {\n return interfaceId == type(IFatIMTReadableStorage).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /// @notice Returns tree `treeId`'s leaves in the half-open range [firstIndex, endIndex).\n /// @dev Overrides the event variant's reader to serve the same selector off the dedicated\n /// `leaves` array. Meant for off-chain `eth_call` (no gas paid); for large ranges page it, since\n /// the return array is bounded by the node's `eth_call` gas/response limits.\n function getFatLeaves(\n uint256 treeId,\n uint256 firstIndex,\n uint256 endIndex\n ) external view virtual override(FatIMTReadableEvent, IFatIMTReadableEvent) returns (uint256[] memory) {\n return InternalFatIMTStorage._getLeaves(_initializedFatStorageTree(treeId), firstIndex, endIndex);\n }\n\n /// @notice Storage slot of tree `treeId`'s `leaves` array header, used by the skinnyfatJs lib to\n /// read leaves directly (`debug_storageRangeAt` / `eth_getStorageAt`).\n /// @dev `leaves` is the first member of `FatIMTDataStorage`, so the struct's slot is the array\n /// header slot; elements start at `keccak256(slot)`. Derived from whatever `_getFatStorageTree`\n /// returns, so it stays correct for a mapping (`keccak256(key, mappingSlot)`) or array layout too.\n function getFatLeavesBaseSlot(uint256 treeId) external view virtual override returns (uint256) {\n FatIMTDataStorage storage tree = _initializedFatStorageTree(treeId);\n uint256 slot;\n assembly {\n slot := tree.slot\n }\n return slot;\n }\n}\n"
180
+ },
181
+ "npm/@warptoad/fat-imt.sol@0.0.11/FatIMTUtils.sol": {
182
+ "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.4;\n\nimport {IIMTEvents} from \"./interfaces/IIMTEvents.sol\";\nimport {SNARK_SCALAR_FIELD} from \"./Constants.sol\";\nimport {FatIMTData} from \"./InternalFatIMTCore.sol\";\n\nerror LeafGreaterThanSnarkScalarField();\n\n// // @TODO ask zemse if the wants to make Poseidon2Yul_BN254 an library with public functions, would add 50~150 gas\n// // Hardcoded since poseidon2 is deployed as a contract instead of a library\n// // This is because author used a gas saving trick with .fallback\n// // address internal constant HASHER_ADDRESS = 0xB2542195Ad96AcfBC962C48A97D7640A9F5386D2;\n// // The function used for hashing. Passed as a function parameter in functions from InternalLazyIMT.\n// // function hasher(uint256[2] memory leaves) internal pure returns (uint256) {\n// // return IPoseidon2(HASHER_ADDRESS).hash_2(leaves[0], leaves[1]);\n// // }\n\n// // The function used for hashing. Passed as a function parameter in functions from InternalLazyIMT.\n// function _poseidon2Hasher(uint256[2] memory leaves) pure returns (uint256) {\n// return LibPoseidon2Yul.hash_2(leaves[0], leaves[1]);\n// }\n\n/// @dev Emits one `UpdatedLeaf` per updated leaf, mirroring `update`.\nfunction _emitUpdatedMany(\n uint256 treeId,\n uint256[] calldata leafIndexes,\n uint256[] memory oldLeaves,\n uint256[] calldata newLeaves\n) {\n for (uint256 i = 0; i < leafIndexes.length; i++) {\n emit IIMTEvents.UpdatedLeaf(treeId, leafIndexes[i], newLeaves[i], oldLeaves[i]);\n }\n}\n\n/// @dev Reverts with `LeafGreaterThanSnarkScalarField` if `v` is not in the BN254 scalar field.\nfunction _requireInField(uint256 v) pure {\n if (v >= SNARK_SCALAR_FIELD) {\n revert LeafGreaterThanSnarkScalarField();\n }\n}\n\n/// @dev Reverts unless every value is within the snark scalar field.\nfunction _requireAllInField(uint256[] calldata values) pure {\n for (uint256 i = 0; i < values.length; i++) {\n _requireInField(values[i]);\n }\n}\n"
183
+ },
184
+ "npm/@warptoad/fat-imt.sol@0.0.11/interfaces/IFatIMTReadableEvent.sol": {
185
+ "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.20;\n\nimport {IERC165} from \"@openzeppelin/contracts/utils/introspection/IERC165.sol\";\n\n/// @title IFatIMTReadableEvent\n/// @dev\ninterface IFatIMTReadableEvent is IERC165 {\n /// @notice Tree `treeId`'s leaves in the half-open range [firstIndex, endIndex).\n function getFatLeaves(\n uint256 treeId,\n uint256 firstIndex,\n uint256 endIndex\n ) external view returns (uint256[] memory);\n\n /// @notice Tree `treeId`'s nodes at `level` in the half-open range [firstIndex, endIndex).\n /// Level 0 is the leaves.\n function getFatNodes(\n uint256 treeId,\n uint256 firstIndex,\n uint256 endIndex,\n uint256 level\n ) external view returns (uint256[] memory);\n\n /// @notice The current root of tree `treeId`.\n function getFatRoot(uint256 treeId) external view returns (uint256);\n\n /// @notice The number of leaves in tree `treeId`.\n function getFatSize(uint256 treeId) external view returns (uint256);\n\n /// @notice The current depth of tree `treeId`.\n function getFatDepth(uint256 treeId) external view returns (uint256);\n}\n"
186
+ },
187
+ "npm/@warptoad/fat-imt.sol@0.0.11/interfaces/IFatIMTReadableStorage.sol": {
188
+ "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.20;\n\nimport {IFatIMTReadableEvent} from \"./IFatIMTReadableEvent.sol\";\n\n/// @title IFatIMTReadableStorage\n/// @dev\ninterface IFatIMTReadableStorage is IFatIMTReadableEvent {\n function getFatLeavesBaseSlot(uint256 treeId) external view returns (uint256);\n}\n"
189
+ },
190
+ "npm/@warptoad/fat-imt.sol@0.0.11/interfaces/IIMTEvents.sol": {
191
+ "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.4;\n\ninterface IIMTEvents {\n event NewLeaf(uint256 indexed treeId, uint256 indexed index, uint256 indexed leaf);\n event UpdatedLeaf(uint256 indexed treeId, uint256 indexed index, uint256 indexed newLeaf, uint256 oldLeaf);\n event RepeatedLeafs(uint256 indexed treeId, uint256 indexed startIndex, uint256 nextIndex, uint256 indexed leaf);\n event NewTree(uint256 indexed treeId);\n event NewRoot(uint256 indexed treeId, uint256 indexed root, uint256 size);\n}\n"
192
+ },
193
+ "npm/@warptoad/fat-imt.sol@0.0.11/InternalFatIMTCore.sol": {
194
+ "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.4;\n\nimport {SNARK_SCALAR_FIELD} from \"./Constants.sol\";\n\n// TODO optimize duplicate inserts by adding hashed from 0 level nodes\nstruct FatIMTData {\n // Tracks the current number of leaves in the tree.\n uint256 size;\n // Represents the current depth of the tree, which can increase as new leaves are inserted.\n uint256 depth;\n // Every node in the tree, keyed by [level][index]. Level 0 holds the leaves, and the\n // root lives at nodes[depth][0]. This allows leaf updates without merkle proofs\n mapping(uint256 => mapping(uint256 => uint256)) nodes;\n uint256 treeId;\n // caches the hash of a repeated value, so instead of doing hash(value,value)\n // you can lookup repeatedHashCache[value]\n mapping(uint256 => uint256) repeatedHashCache;\n}\n\nstruct MultiProof {\n uint256 treeDepth;\n uint256 edgeIndex;\n uint256[] leafIndexes;\n uint256[] proofSiblings;\n}\n\nerror WrongSiblingNodes();\nerror LeafDoesNotExist();\nerror WrongMultiProof();\nerror TreeEmpty();\n\n/// @title Fat Incremental binary Merkle tree.\n/// @dev The FatIMT is an optimized version of the BinaryIMT.\n/// This implementation eliminates the use of pre-inserted zeroes, and make the tree depth dynamic.\n/// When a node doesn't have the right child, instead of using a zero hash as in the BinaryIMT,\n/// the node's value becomes that of its left child. Furthermore, rather than utilizing a static tree depth,\n/// it is updated based on the number of leaves in the tree. This approach\n/// results in the calculation of significantly fewer hashes, making the tree more efficient.\nlibrary InternalFatIMTCore {\n function _reset(FatIMTData storage self) internal {\n self.size = 0;\n self.depth = 0;\n self.nodes[0][0] = 0; // so _root does not reference an old leaf when it's still empty\n }\n\n /// @dev self.nodes getter (to stay under stack limit)\n function _getNode(FatIMTData storage self, uint256 index, uint256 level) internal view returns (uint256) {\n return self.nodes[level][index];\n }\n\n /// @dev self.nodes setter (to stay under stack limit)\n function _setNode(FatIMTData storage self, uint256 index, uint256 value, uint256 level) private {\n self.nodes[level][index] = value;\n }\n\n /// @dev self.nodes getter (to stay under stack limit)\n /// writes a batch of nodes for one level\n function _setNodes(\n FatIMTData storage self,\n uint256 level,\n uint256 startIndex,\n uint256[] memory levelNodes\n ) private {\n for (uint256 i = 0; i < levelNodes.length; ) {\n self.nodes[level][startIndex + i] = levelNodes[i];\n unchecked {\n ++i;\n }\n }\n }\n\n /// @dev used in _insertManyRepeated (to stay under stack limit)\n /// writes all the nodes of one level from _insertManyRepeated:\n /// the left and right boundary node (who might differ from the repeating hashes)\n /// and the repeating nodes in between those (who always share the same value).\n /// @notice once indexes match up, this function choose rightEdgeNode above: leftBoundaryNode and centerRepeatingNode\n /// this means that, in that case leftBoundaryNode and centerRepeatingNode are allowed to be stale.\n function _setRepeatedRange(\n FatIMTData storage self,\n uint256 level,\n uint256 leftIndex,\n uint256 rightIndex,\n uint256 leftBoundaryNode,\n uint256 centerRepeatingNode,\n uint256 rightEdgeNode\n ) private {\n mapping(uint256 => uint256) storage levelNodes = self.nodes[level];\n\n // rightEdge is authoritative at rightIndex, always write it\n levelNodes[rightIndex] = rightEdgeNode;\n\n // only write if they are at different indexes\n if (leftIndex < rightIndex) {\n levelNodes[leftIndex] = leftBoundaryNode;\n }\n // fill in the gap with centerRepeatingNode. If there is any, otherwise ignore centerRepeatingNode\n for (uint256 index = leftIndex + 1; index < rightIndex; ) {\n levelNodes[index] = centerRepeatingNode;\n unchecked {\n ++index;\n }\n }\n }\n\n /// @dev Inserts a new leaf into the incremental merkle tree.\n /// @notice Does not do field checks. For that use `InternalFatIMTEvent._insertBN254()`\n /// @param self: A storage reference to the 'FatIMTData' struct.\n /// @param leaf: The value of the new leaf to be inserted into the tree.\n /// @return (root, index) root: the new root, index: index leaf landed at\n function _insert(\n FatIMTData storage self,\n uint256 leaf,\n function(uint256[2] memory) view returns (uint256) hasher\n ) internal returns (uint256, uint256) {\n // init check moved to the Event layer (folded into the treeId read the event already does)\n uint256 index = self.size;\n\n // Cache tree depth to optimize gas\n uint256 treeDepth = self.depth;\n\n // A new insertion can increase a tree's depth by at most 1,\n // and only if the number of leaves supported by the current\n // depth is less than the number of leaves to be supported after insertion.\n if ((1 << treeDepth) < index + 1) {\n ++treeDepth;\n }\n\n self.depth = treeDepth;\n\n uint256 node = leaf;\n\n // position of `node` at the current level, starting at the leaf index.\n uint256 nodeIndex = index;\n\n // store the leaf itself at level 0\n self.nodes[0][nodeIndex] = node;\n\n for (uint256 level = 0; level < treeDepth; ) {\n if (nodeIndex & 1 == 1) {\n // right child: hash with the left sibling\n // Tree fills left to right, and we carry up any even indexes until they're uneven,\n // so we only hash on the \"node is right\" case\n // This feels weird, since it sounds like an leaf at even index at lets say 8 that:\n //_hashMultiProofLevel needs to be hashed left in a balanced of size 16 tree\n // so `hash(index_8, index_9)`\n // That does happen, but at the next insert. Next insert does: `hash(index_8, index_9)`\n // where index_8 is read from storage (`self.nodes[level][index_9 - 1]`)\n node = hasher([self.nodes[level][nodeIndex - 1], node]);\n }\n // else {\n // left child (even pos): node dangles and becomes its own parent, carried up unchanged\n // until it hits a uneven pos, then it joins the tree by hashing with a subtree (`hash(subtree, node)`)\n // }\n\n // shift index to next level, store every node\n nodeIndex >>= 1;\n self.nodes[level + 1][nodeIndex] = node;\n\n unchecked {\n ++level;\n }\n }\n\n // the last iteration stored the root at nodes[treeDepth][0] (nodeIndex collapses to 0)\n // original did self.size = index++ above\n // since self.leaves[leaf] = index + 1. But that is no longer true\n self.size = index + 1;\n return (node, index);\n }\n\n /// @dev Per-level index/size trackers for `_insertMany`, bundled into one memory slot (one stack\n /// slot instead of four) so the function can also return the start/next indexes without blowing\n /// the 16-slot stack (no viaIR). Mutated in place as we climb: `currentLevel*` is the level being\n /// consumed, `nextLevel*` the level being built.\n struct InsertManyLevel {\n uint256 currentLevelStartIndex; // first index to change at the current level\n uint256 currentLevelSize; // number of nodes at the current level\n uint256 nextLevelStartIndex; // first index to change at the next level\n uint256 nextLevelSize; // number of nodes at the next level\n }\n\n /// @dev Inserts many leaves into the incremental merkle tree.\n /// @notice Contracts using this function with snark based hash functions,\n // need to check that the leafs are within the snark scalar field.\n /// @param self: A storage reference to the 'FatIMTData' struct.\n /// @param leaves: The values of the new leaves to be inserted into the tree.\n /// @return root after the leaves have been inserted.\n /// @return startIndex index of the first appended leaf (inclusive).\n /// @return nextIndex index one past the last appended leaf (exclusive). Same shape as\n /// `_insertManyRepeated`. The per-level trackers are packed in an `InsertManyLevel` struct so the\n /// frame has room for the two extra return values under the 16-slot stack limit (no viaIR).\n function _insertMany(\n FatIMTData storage self,\n uint256[] calldata leaves,\n function(uint256[2] memory) view returns (uint256) hasher\n ) internal returns (uint256, uint256, uint256) {\n // init check moved to the Event layer (folded into the treeId read the event already does)\n // cache treeSize (this is also the startIndex)\n uint256 startIndex = self.size;\n\n // Array to save the nodes that will be used to create the next level of the tree.\n uint256[] memory currentLevelNewNodes;\n\n currentLevelNewNodes = leaves;\n\n // store the new leaves at level 0\n for (uint256 i = 0; i < leaves.length; ) {\n self.nodes[0][startIndex + i] = leaves[i];\n unchecked {\n ++i;\n }\n }\n\n // Cache tree depth to optimize gas\n uint256 treeDepth = self.depth;\n\n // Calculate the depth of the tree after adding the new values.\n // Unlike the 'insert' function, we need a while here as\n // N insertions can increase the tree's depth more than once.\n while ((1 << treeDepth) < startIndex + leaves.length) {\n ++treeDepth;\n }\n self.depth = treeDepth;\n\n // Update tree size up front so `oldTreeSize` is no longer needed inside the level loop below,\n // freeing a stack slot in that already stack-tight loop.\n self.size = startIndex + leaves.length;\n\n // The four per-level trackers, in one memory slot\n InsertManyLevel memory lvl = InsertManyLevel({\n currentLevelStartIndex: startIndex,\n currentLevelSize: startIndex + leaves.length,\n nextLevelStartIndex: startIndex >> 1, // currentLevelStartIndex / 2\n nextLevelSize: ((startIndex + leaves.length - 1) >> 1) + 1 // ceil(currentLevelSize / 2)\n });\n\n for (uint256 level = 0; level < treeDepth; ) {\n // The number of nodes for the new level that will be created,\n // only the new values, not the entire level.\n uint256[] memory nextLevelNewNodes = new uint256[](lvl.nextLevelSize - lvl.nextLevelStartIndex);\n\n for (uint256 i = 0; i < lvl.nextLevelSize - lvl.nextLevelStartIndex; ) {\n // packing left and right node in one array saves on the stack size\n uint256[2] memory hasherInput;\n\n // Only the first node (i==0) can border the existing tree, and only when currentLevelStartIndex is\n // odd: then its left sibling is read from storage. Otherwise both children are in memory\n // (currentLevelNewNodes). Reading it here (not precomputed) keeps the stack slim.\n if (i == 0 && lvl.currentLevelStartIndex & 1 == 1) {\n hasherInput[0] = self.nodes[level][lvl.nextLevelStartIndex * 2];\n } else {\n hasherInput[0] = currentLevelNewNodes[\n (i + lvl.nextLevelStartIndex) * 2 - lvl.currentLevelStartIndex\n ];\n }\n // `i` counts parents so we reconstruct it's left childs index by doing:`(i + nextLevelStartIndex) << 1`\n // then +1 and we have the right child's index\n // then if that *right* child lays at or out side of currentLevelSize, it means we don't have the -\n // the *right* child rn, so we hoist the *left* child (we do have) up,\n /// to be hashed in *a* another iteration\n if (((i + lvl.nextLevelStartIndex) << 1) + 1 < lvl.currentLevelSize) {\n hasherInput[1] = currentLevelNewNodes[\n ((i + lvl.nextLevelStartIndex) << 1) + 1 - lvl.currentLevelStartIndex\n ];\n // store as parent node for next round\n nextLevelNewNodes[i] = hasher(hasherInput);\n } else {\n // leave to dangle:\n // node is used in next iter, becomes it's own parent.\n // Stored in nextLevelNewNodes, for when it will have an right sibling eventually\n // store as parent node for next round\n nextLevelNewNodes[i] = hasherInput[0];\n }\n\n unchecked {\n ++i;\n }\n }\n\n // store every node (outside loop with helper because of stack limit)\n _setNodes(self, level + 1, lvl.nextLevelStartIndex, nextLevelNewNodes);\n\n lvl.currentLevelStartIndex = lvl.nextLevelStartIndex;\n\n // Calculate the next level startIndex value.\n // It is the position of the parent node which is pos/2.\n lvl.nextLevelStartIndex >>= 1;\n\n // Update the next array that will be used to calculate the next level.\n currentLevelNewNodes = nextLevelNewNodes;\n\n lvl.currentLevelSize = lvl.nextLevelSize;\n\n // Calculate the size of the next level.\n // The size of the next level is ceil(n / 2) (-1 +1 to efficiently mimic ceil).\n // rounded up since odd levelSize would result in a dangle being hoisted up,\n // so round up to include that hoisted node\n lvl.nextLevelSize = ((lvl.nextLevelSize - 1) >> 1) + 1;\n\n unchecked {\n ++level;\n }\n }\n\n // the loop already stored the root at nodes[treeDepth][0]; keep this explicit\n // we could also store as a safety net for the top of the tree.\n // self.nodes[treeDepth][0] = currentLevelNewNodes[0];\n\n return (currentLevelNewNodes[0], startIndex, startIndex + leaves.length);\n }\n\n /// @dev Returns `hasher(value, value)`\n // from cache if it has it, hashed fresh if not\n // also stores the fresh hash for future use\n /// per-iteration stack under Solidity's 16-slot limit.\n /// @param self: A storage reference to the 'FatIMTData' struct.\n /// @param value: The value to hash with itself.\n /// @return `hasher(currentNode, currentNode)`.\n function _hashWithCache(\n FatIMTData storage self,\n uint256 value,\n function(uint256[2] memory) view returns (uint256) hasher\n ) private returns (uint256) {\n uint256 cached = self.repeatedHashCache[value];\n if (cached != 0) {\n return cached;\n }\n uint256 hash = hasher([value, value]);\n self.repeatedHashCache[value] = hash;\n return hash;\n }\n\n /// @dev Efficiently appends n-`amount` many leaves, with the same value in the tree.\n /// @notice Worst case hash cost is 3*newDepth hashes regardless of `amount`.\n /// Best case cost 1*newDept. However storage is O(amount): since the fat variant is forced to store all nodes\n /// Only the hashing keeps the O(newTreeDepth) repeated-subtree optimization.\n ///\n /// Only hashes 3 paths:\n /// repeatedCenterNode: in the center of the insert,\n /// these only contain nodes of \"a balanced tree with only the same value repeating\".\n /// ex: H(0,0), H(H(0,0),H(0,0)), etc\n /// Majority of the hashes are the same as a repeatedCenterNode at every level.\n /// Re-using those hashes instead of re-hashing is the core of the optimization here\n /// lefBoundaryNodes: at the left of the insert who mix with the existing tree.\n /// rightEdgeNodes: at the right of the insert and tree, tracks potential dangling nodes to to root\n /// Eventually meets lefBoundaryNodes and creates the root.\n ///\n /// both lefBoundaryNodes and rightEdgeNodes use repeatedCenterNode to attach to the rest of the inserted sub tree.\n /// Best case cost is O(1*newDepth) because both lefBoundaryNodes and rightEdgeNodes,\n /// will use nodes from repeatedCenterNode when ever they can.\n /// And when a insert results in an balanced tree and previous tree is empty, that is alway the case.\n /// So it will always be O(1*newTreeDepth)\n /// @param self: A storage reference to the 'FatIMTData' struct.\n /// @param value: The leaf value to insert `amount` copies of.\n /// @param amount: The number of leaves to append.\n /// @return root after the leaves have been appended.\n /// @return startIndex index of the first appended leaf (inclusive).\n /// @return nextIndex index one past the last appended leaf (exclusive), matching the Event layer.\n function _insertManyRepeated(\n FatIMTData storage self,\n uint256 value,\n uint256 amount,\n function(uint256[2] memory) view returns (uint256) hasher\n ) internal returns (uint256 root, uint256 startIndex, uint256 nextIndex) {\n uint256 newTreeDepth = self.depth;\n startIndex = self.size;\n // NOTE: named returns are load-bearing here — this frame is stack-tight (no viaIR) and\n // de-naming these into locals overflows it (verified). We return the exclusive `nextIndex`\n // and derive the inclusive last index inline as `(nextIndex - 1)` to occupy one less slot.\n {\n nextIndex = startIndex + amount;\n while (1 << newTreeDepth < nextIndex) {\n unchecked {\n ++newTreeDepth;\n }\n }\n\n // init check moved to the Event layer\n if (amount == 0) {\n // nothing appended: the exclusive end is startIndex itself\n return (_root(self), startIndex, startIndex);\n }\n if (amount == 1) {\n (root, ) = _insert(self, value, hasher);\n return (root, startIndex, nextIndex);\n }\n\n self.depth = newTreeDepth;\n self.size = nextIndex;\n }\n\n // Nodes used in hashing at the edges of the insert and the center where the node only contains zeros:\n // lefBoundaryNode = The node at the boundary between the insert and existing tree.\n // rightEdgeNode = The node that is at the very edge of the tree.\n // repeatedCenterNode = The node that all sit in the center of the insert and\n // only contain repeated values and is always balanced. Always cache-able\n uint256 leftBoundaryNode = value;\n uint256 rightEdgeNode = value;\n uint256 repeatedCenterNode = value;\n\n // loops only once over the newTreeDepth\n // does at most 3 hashes,\n // 2 hashes for the left and right side of the inserted values (lefEdgeNode, rightEdgeNode)\n // 1 hash / cache lookup for the node that only contains zeros (repeatedCenterNode)\n for (uint256 level = 0; level < newTreeDepth; ) {\n // ------------assign sideNode --------------\n // oldSideNode is only actually consumed when the left boundary sits at an odd position\n // (the newSideNode == oldSideNode branch and the leftBoundary hashing below). At those\n // levels the node right before the boundary is the existing tree's frontier, stored at\n // its real index. When the boundary is even oldSideNode is read but never used, so 0 is fine.\n uint256 oldSideNode = ((startIndex >> level) & 1 == 1) ? self.nodes[level][(startIndex >> level) - 1] : 0;\n uint256 newSideNode;\n {\n // calculate the current index of the most left and right node of the insert\n // by doing: index >> level (same as: index / 2^level). (nextIndex - 1) is the inclusive\n // last leaf index; see the note at the top on why we don't keep it in its own slot.\n uint256 rightEdgePosition = (nextIndex - 1) >> level;\n uint256 leftBoundaryPosition = startIndex >> level;\n\n // determine where the sideNode is at. Left,right, (somewhere) center of the inserted nodes or unchanged\n // sideNode == rightEdgeNodeSibling (left sibling of rightEdge), unless dangles or if root\n if (rightEdgePosition & 1 == 0) {\n // here rightEdgeNode is at an uneven index, because it is at the very edge of the entire tree,\n // it will have no sibling :(, it will \"dangle\" and thus will be the newSideNode\n newSideNode = rightEdgeNode;\n\n // these cases when rightEdgeNode does have a sibling :D\n // now we just detect who is that sibling. leftBoundary, repeatedCenter or oldSideNode?\n } else if (leftBoundaryPosition < (rightEdgePosition - 1)) {\n // rightEdgeNode has a sibling :D\n // But that sibling is not leftBoundaryPosition yet, since the position of\n // the sibling of rightEdgeNode (rightEdgePosition - 1) is higher then leftBoundaryPosition\n // There for we need a sibling between the old tree and the very right edge,\n // we need repeatedCenterNode!\n newSideNode = repeatedCenterNode;\n } else if (leftBoundaryPosition == (rightEdgePosition - 1)) {\n // Now rightEdgeNode's sibling positions is *exactly* leftBoundaryPosition\n // it's sibling is leftBoundaryNode!\n newSideNode = leftBoundaryNode;\n } else {\n // now leftBoundaryPosition is the same as rightEdgePosition\n // we know this because leftBoundaryPosition < rightEdgeSiblingPosition (else if #1)\n // and leftBoundaryPosition != rightEdgeSiblingPosition (else if #2)\n // and because node position only converge when moving up a tree, but never cross,\n // we can now say leftBoundaryNode is at the same position as rightEdgeNode\n // because leftBoundaryNode and rightEdgeNode are the same, they form a subTreeRoot that contains\n // all values we are inserting (sometimes some values of existing tree).\n // Now we need to just \"attach\" this root with our inserts to the existing tree\n // simply by constantly hashing in the oldSideNode of that level.\n newSideNode = oldSideNode;\n }\n }\n\n // stores all repeated nodes and boundary node at this level.\n _setRepeatedRange(\n self,\n level,\n startIndex >> level,\n (nextIndex - 1) >> level,\n // leftBoundaryNode goes stale when leftIndex == rightIndex,\n // but this function ignores leftBoundaryNode at that point.\n leftBoundaryNode,\n repeatedCenterNode,\n rightEdgeNode\n );\n\n //-------- hashing -----------------\n {\n // ---- repeatedCenterNode---\n // newRepeatedCenterNode use a cache to look hashes from a \"balanced tree with only repeated values\"\n uint256 newRepeatedCenterNode = _hashWithCache(self, repeatedCenterNode, hasher);\n\n // ----leftBoundaryNode---\n // calculate index of the left boundary node at this level and check if it's odd or even, left or right\n // oldSize / (2**level) % 2\n {\n // redoing calculation here because of stack limits\n // uint256 leftBoundaryPosition = startIndex >> level; over stack limit again :/\n uint256 nextRightEdgePosition = (nextIndex - 1) >> (level + 1);\n uint256 nextLeftEdgePosition = startIndex >> (level + 1);\n\n // we can skip leftBoundaryNode if the next iter rightEdgeNode is at the same position\n // at that point leftBoundaryNode does the same as rightEdgeNode,\n // so no need to do things twice\n if (nextLeftEdgePosition != nextRightEdgePosition) {\n // if leftBoundaryPosition is right\n if ((startIndex >> level) & 1 == 1) {\n // if right use oldSideNode, since that is where these added nodes \"attach\" to the\n // existing tree\n if (leftBoundaryNode == repeatedCenterNode && oldSideNode == repeatedCenterNode) {\n // no need to hash, already done by newRepeatedCenterNode!\n // oldSideNode was just a N-hashed repeated value\n leftBoundaryNode = newRepeatedCenterNode;\n } else {\n // existing tree had something else, no luck!\n leftBoundaryNode = hasher([oldSideNode, leftBoundaryNode]);\n }\n } else {\n // if left, use the repeatedCenterNode,\n // (could be one if but requires another var on the stack)\n if (leftBoundaryNode == repeatedCenterNode) {\n // no need to hash, already done by newRepeatedCenterNode!\n leftBoundaryNode = newRepeatedCenterNode;\n } else {\n // our boundary node picked up an existing value from the existing tree\n // that is not our value we are repeatedly inserting. No luck :(\n leftBoundaryNode = hasher([leftBoundaryNode, repeatedCenterNode]);\n }\n }\n }\n }\n\n // ---- rightEdgeNode ---\n // calculate index of the newSide node at this level and check if it's odd or even\n // rightEdgePosition = ((nextIndex - 1) / (2**level)) % 2\n if (((nextIndex - 1) >> level) & 1 == 1) {\n // if odd rightEdgeNode has a sibling so we hash it right\n if (newSideNode == rightEdgeNode) {\n // we are doing hasher([rightEdgeNode, rightEdgeNode])\n if (repeatedCenterNode == rightEdgeNode) {\n // it's just a center node\n rightEdgeNode = newRepeatedCenterNode;\n } else {\n // we might be doing hasher([rightEdgeNode, rightEdgeNode])\n // as a coincidence. Or we did do a \"balanced tree with only repeated values\" hash\n // check the cache\n uint256 cached = self.repeatedHashCache[rightEdgeNode];\n if (cached != 0) {\n rightEdgeNode = cached; // free hash\n } else {\n // not storing this because it might have been a coincidence\n rightEdgeNode = hasher([rightEdgeNode, rightEdgeNode]);\n }\n }\n } else {\n rightEdgeNode = hasher([newSideNode, rightEdgeNode]);\n }\n }\n // we don't do the left case since we need to leave rightEdgeNode to dangle\n\n // repeatedCenterNode updates for the next iter\n repeatedCenterNode = newRepeatedCenterNode;\n }\n\n // Advance level first so it doubles as `nextLevel` for the cache lift.\n unchecked {\n ++level;\n }\n }\n\n // finally store the root!\n root = rightEdgeNode;\n self.nodes[newTreeDepth][0] = root;\n return (root, startIndex, nextIndex);\n }\n\n /// @dev Warms the `(value, level)` cache for levels 1..`upToLevel` so that\n /// subsequent `_insertManyRepeated(value, ...)` calls hit the cache instead of\n /// re-hashing. Idempotent: levels already cached are not rewritten.\n /// @notice Useful when you know in advance the maximum depth a tree will reach\n /// for a particular `value` (e.g. zero) — pay the SSTOREs once, then every\n /// subsequent bulk-insert of that value reads cheaply from storage.\n /// @notice Reverts if the tree has not been initialized.\n /// @param self: A storage reference to the 'FatIMTData' struct.\n /// @param value: The leaf value whose repeated-subtree chain to precompute.\n /// @param upToLevel: The highest level (inclusive) to populate the cache for.\n function _precomputeRepeatedCache(\n FatIMTData storage self,\n uint256 value,\n uint256 upToLevel,\n function(uint256[2] memory) view returns (uint256) hasher\n ) internal {\n // init check moved to the Event layer (folded into the treeId read the event already does)\n if (upToLevel == 0) {\n return;\n }\n\n // subtreeRoot tracks the repeated-subtree root at the current level as we\n // climb. Start at level 0 = value. Each iteration looks up (or fills)\n // hasher(subtreeRoot, subtreeRoot) and advances one level.\n uint256 subtreeRoot = value;\n for (uint256 level = 1; level <= upToLevel; ) {\n subtreeRoot = _hashWithCache(self, subtreeRoot, hasher);\n unchecked {\n ++level;\n }\n }\n }\n\n /// @dev Updates the value of an existing leaf and re-hashes its path to the root, persisting every\n /// recomputed node at its real index. Reads each sibling straight from storage — the left sibling\n /// (`nodes[level][pos - 1]`) for a right child, the right sibling (`nodes[level][pos + 1]`) for a\n /// left child — unless the node is the dangling right edge at that level (`pos == edgeIndex >> level`),\n /// which has no sibling and is carried up unchanged. No merkle proof and no caller-supplied oldLeaf\n /// is required; the old value is read from storage and returned (for the event).\n /// @param self: A storage reference to the 'FatIMTData' struct.\n /// @param newLeaf: The new value that will replace the current leaf.\n /// @param leafIndex: The index of the leaf to be updated.\n /// @return newRoot The new root after the leaf has been updated.\n /// @return oldLeaf The value the leaf held before the update.\n /// @notice Reverts with LeafDoesNotExist if leafIndex is out of range. Contracts using this\n /// function with snark based hash functions need to check that newLeaf is within the snark\n /// scalar field.\n function _update(\n FatIMTData storage self,\n uint256 newLeaf,\n uint256 leafIndex,\n function(uint256[2] memory) view returns (uint256) hasher\n ) internal returns (uint256, uint256) {\n // init check moved to the Event layer (folded into the treeId read the event already does)\n uint256 treeSize = self.size;\n if (leafIndex >= treeSize) {\n revert LeafDoesNotExist();\n }\n\n uint256 oldLeaf = self.nodes[0][leafIndex];\n\n // overwrite the leaf, then climb re-hashing its path. `leafIndex` doubles as the climbing\n // position and `newRoot` as the running node; both collapse to the root at the top.\n uint256 newRoot = newLeaf;\n self.nodes[0][leafIndex] = newLeaf;\n\n uint256 treeDepth = self.depth;\n uint256 edgeIndex = treeSize - 1;\n for (uint256 level = 0; level < treeDepth; ) {\n if (leafIndex & 1 == 1) {\n // right child: hash with the stored left sibling\n newRoot = hasher([self.nodes[level][leafIndex - 1], newRoot]);\n } else if (leafIndex != edgeIndex >> level) {\n // left child that has a right sibling present in the tree\n newRoot = hasher([newRoot, self.nodes[level][leafIndex + 1]]);\n }\n // else: dangling right edge at this level, carried up unchanged\n\n // move up a level and store the recomputed parent at its index\n leafIndex >>= 1;\n self.nodes[level + 1][leafIndex] = newRoot;\n\n unchecked {\n ++level;\n }\n }\n return (newRoot, oldLeaf);\n }\n\n /// @dev Hashes merkle proof and returns the root the leaf belongs to\n /// @param leafIndex: The leaf to proof inclusion of\n /// @param leafIndex: The index of the leaf within the tree.\n /// @param proofSiblings: The sibling nodes along the path from the leaf to the root.\n /// @return The root obtained from hashing the leaf with the provided siblings.\n /// @notice Contracts using this function with snark based hash functions,\n /// need to check that the leaf and proofSiblings are within the snark scalar field.\n function _proofToRoot(\n uint256 treeDepth,\n uint256 treeSize,\n uint256 leaf,\n uint256 leafIndex,\n uint256[] calldata proofSiblings,\n function(uint256[2] memory) view returns (uint256) hasher\n ) internal view returns (uint256) {\n if (treeSize == 0) {\n revert TreeEmpty();\n }\n\n // index of the very last leaf in the tree\n // tracking this index up the tree, follows the indexes of the nodes in self.sidNodes\n uint256 edgeIndex = treeSize - 1;\n\n // because leanIMT is not balanced proofSiblings.length can be smaller then tree depth\n // we cant just use level so we separately track those 2\n uint256 siblingIndex = 0;\n\n uint256 node = leaf;\n for (uint256 level = 0; level < treeDepth; ) {\n if ((leafIndex >> level) & 1 == 1) {\n node = hasher([proofSiblings[siblingIndex], node]);\n\n unchecked {\n ++siblingIndex;\n }\n } else {\n // make sure node index is not at the edge @TODO explain\n if (leafIndex >> level != edgeIndex >> level) {\n node = hasher([node, proofSiblings[siblingIndex]]);\n\n unchecked {\n ++siblingIndex;\n }\n }\n }\n\n unchecked {\n ++level;\n }\n }\n return node;\n }\n\n struct MultiProofLevel {\n // One level's known nodes and their positions. The fold rewrites parents in place into\n // the low end of these same arrays: the write cursor (nextNodesFreeSlot) never runs ahead\n // of the read index, and the only forward read (the i+1 sibling) is always still unwritten,\n // so a single buffer aliases safely. `currentNodesFreeSlot` bounds the live prefix.\n uint256[] nodes;\n uint256[] positions;\n }\n\n struct MultiProofArrLevelPositions {\n uint256 currentNodesFreeSlot;\n uint256 nextNodesFreeSlot;\n uint256 proofSiblingsReadPos;\n uint256 edgePos;\n uint256 level;\n }\n\n /// @dev Folds one tree level: reads the known nodes in `nodes` (positions in `positions`)\n /// and rewrites their parents into the low end of those same arrays in place,\n /// pulling a sibling from `proof.proofSiblings` only where one isn't already known.\n /// A rightmost node with no sibling (position == edgePos) is carried up unchanged — this\n /// is where dangling (a leaf or an internal node with no right neighbor) is resolved,\n /// entirely from the tree's `edgeIndex`, not from any caller-supplied schedule.\n function _hashMultiProofLevel(\n MultiProof memory proof,\n MultiProofLevel memory lvl,\n MultiProofArrLevelPositions memory lvlPos,\n function(uint256[2] memory) view returns (uint256) hasher\n ) private view returns (MultiProofLevel memory, MultiProofArrLevelPositions memory) {\n for (uint256 i = 0; i < lvlPos.currentNodesFreeSlot; i++) {\n // hash left or right\n if (lvl.positions[i] & 1 == 1) {\n // A right-position node whose sibling is also known is consumed at that sibling\n // (the even node below, which skips forward past this one), so reaching here means\n // the left sibling isn't in currentNodes and must come from the proof.\n lvl.nodes[lvlPos.nextNodesFreeSlot] = hasher(\n [proof.proofSiblings[lvlPos.proofSiblingsReadPos], lvl.nodes[i]]\n );\n lvl.positions[lvlPos.nextNodesFreeSlot] = lvl.positions[i] >> 1;\n\n unchecked {\n ++lvlPos.nextNodesFreeSlot;\n ++lvlPos.proofSiblingsReadPos;\n }\n } else {\n // make sure node index is not at the edge because edges should be carried up a level\n // TODO these variable names are so long the auto format makes the code unreadable\n if (lvl.positions[i] != lvlPos.edgePos) {\n if ((i + 1) < lvlPos.currentNodesFreeSlot && (lvl.positions[i + 1] == (lvl.positions[i] + 1))) {\n // the right sibling is the next node in currentNodes, so hash the pair\n // here and skip it (avoids reading a left neighbor on the next iteration)\n lvl.nodes[lvlPos.nextNodesFreeSlot] = hasher([lvl.nodes[i], lvl.nodes[i + 1]]);\n lvl.positions[lvlPos.nextNodesFreeSlot] = lvl.positions[i] >> 1;\n // up counter to skip next node since we already hashed it.\n unchecked {\n ++i;\n }\n } else {\n lvl.nodes[lvlPos.nextNodesFreeSlot] = hasher(\n [lvl.nodes[i], proof.proofSiblings[lvlPos.proofSiblingsReadPos]]\n );\n lvl.positions[lvlPos.nextNodesFreeSlot] = lvl.positions[i] >> 1;\n\n unchecked {\n ++lvlPos.proofSiblingsReadPos;\n }\n }\n } else {\n lvl.nodes[lvlPos.nextNodesFreeSlot] = lvl.nodes[i];\n lvl.positions[lvlPos.nextNodesFreeSlot] = lvl.positions[i] >> 1;\n }\n ++lvlPos.nextNodesFreeSlot;\n }\n }\n\n // per level updates\n lvlPos.edgePos >>= 1;\n\n // parents were written in place into the low slots; that prefix is the next level.\n lvlPos.currentNodesFreeSlot = lvlPos.nextNodesFreeSlot;\n lvlPos.nextNodesFreeSlot = 0;\n return (lvl, lvlPos);\n }\n\n // would save 2 array in memory, more importantly stack pressure\n function _proofManyToRoot(\n uint256[] calldata leaves,\n MultiProof memory proof,\n function(uint256[2] memory) view returns (uint256) hasher\n ) internal view returns (uint256) {\n uint256 leafCount = leaves.length;\n if (leafCount == 0 || leafCount != proof.leafIndexes.length) {\n revert WrongMultiProof();\n }\n\n MultiProofLevel memory lvl = MultiProofLevel(new uint256[](leafCount), new uint256[](leafCount));\n\n MultiProofArrLevelPositions memory lvlPos = MultiProofArrLevelPositions(0, 0, 0, proof.edgeIndex, 0);\n\n // Seed every proven leaf at level 0, at its real index. Each leaf is then hashed up\n // from the bottom, so an internal-node value or a wrong index simply produces a\n // non-matching root — nothing can enter above level 0 un-hashed. Dangling is resolved\n // while climbing (the edge-carry in _hashMultiProofLevel), derived from `edgeIndex`.\n for (uint256 i = 0; i < leafCount; i++) {\n lvl.nodes[i] = leaves[i];\n lvl.positions[i] = proof.leafIndexes[i];\n }\n lvlPos.currentNodesFreeSlot = leafCount;\n\n for (uint256 level = 0; level < proof.treeDepth; ) {\n lvlPos.level = level;\n (lvl, lvlPos) = _hashMultiProofLevel(proof, lvl, lvlPos, hasher);\n\n unchecked {\n ++level;\n }\n }\n\n // all proof siblings need to be read and validated.\n // Very strict but now this function verifies leaves + indexes + proof siblings\n if (lvlPos.proofSiblingsReadPos != proof.proofSiblings.length) {\n revert WrongMultiProof();\n }\n return lvl.nodes[0];\n }\n\n // Per-level scalars for the batch-update fold. Bundled into a struct (mutated in place, like\n // MultiProofLevelState) so _updateManyLevel takes few enough arguments to stay under the stack limit.\n struct UpdateManyLevel {\n uint256 count; // number of known nodes at this level (live prefix of the state arrays)\n /// TODO make more human readable, audit etc\n uint256 edgePos; // position of the dangling right edge at this level (treeSize-1 >> level)\n uint256 level; // current level\n }\n\n /// @dev _updateMany cant re-use _hashMultiProofLevel like in skinny-imt since it assumes a merkle proof exists\n /// this function efficiently walks up one level of the hash path of multiple nodes in an update\n /// it loops\n function _updateManyLevel(\n FatIMTData storage self,\n MultiProofLevel memory lvl,\n UpdateManyLevel memory lvlPos,\n function(uint256[2] memory) view returns (uint256) hasher\n ) private returns (MultiProofLevel memory, UpdateManyLevel memory) {\n uint256 writeSlot = 0;\n for (uint256 i = 0; i < lvlPos.count; ) {\n uint256 nodeIndex = lvl.positions[i];\n uint256 parent;\n\n if (nodeIndex & 1 == 1) {\n // right child: its left sibling is never a known node here, read it from storage\n parent = hasher([_getNode(self, nodeIndex - 1, lvlPos.level), lvl.nodes[i]]);\n } else if (nodeIndex == lvlPos.edgePos) {\n // dangling right edge: no sibling, carried up unchanged\n parent = lvl.nodes[i];\n } else if (i + 1 < lvlPos.count && lvl.positions[i + 1] == nodeIndex + 1) {\n // the right sibling is the next known node: joined paths meet, hash the pair once\n parent = hasher([lvl.nodes[i], lvl.nodes[i + 1]]);\n unchecked {\n ++i;\n }\n } else {\n // left child whose right sibling is untouched: read it from storage\n parent = hasher([lvl.nodes[i], _getNode(self, nodeIndex + 1, lvlPos.level)]);\n }\n\n uint256 parentPos = nodeIndex >> 1;\n _setNode(self, parentPos, parent, lvlPos.level + 1);\n lvl.nodes[writeSlot] = parent;\n lvl.positions[writeSlot] = parentPos;\n\n unchecked {\n ++writeSlot;\n ++i;\n }\n }\n\n // advance to the next level\n lvlPos.count = writeSlot;\n lvlPos.edgePos >>= 1;\n lvlPos.level += 1;\n return (lvl, lvlPos);\n }\n\n /// @dev Seeds level 0 of a batch update: validates each index, records the old leaf, writes the\n /// new leaf, and fills `state` with the new leaves at their indexes. Split into its own frame so\n /// `_updateMany` stays under the 16-slot stack limit.\n /// @return oldLeaves The values the leaves held before the update.\n function _seedUpdateMany(\n FatIMTData storage self,\n uint256[] calldata newLeaves,\n uint256[] calldata leafIndexes,\n MultiProofLevel memory lvl,\n uint256 treeSize\n ) private returns (uint256[] memory) {\n uint256[] memory oldLeaves = new uint256[](newLeaves.length);\n for (uint256 i = 0; i < newLeaves.length; ) {\n uint256 leafIndex = leafIndexes[i];\n if (leafIndex >= treeSize) {\n revert LeafDoesNotExist();\n }\n // Must be strictly ascending (no dupes) so joined siblings sit adjacent. Skinny caught a\n // bad order via its old-root check; here we just rebuild and write the root, so a wrong\n // order isn't caught — it would persist a wrong root. Hence enforce it.\n if (i != 0 && leafIndex <= leafIndexes[i - 1]) {\n revert WrongMultiProof();\n }\n oldLeaves[i] = _getNode(self, leafIndex, 0);\n lvl.nodes[i] = newLeaves[i];\n lvl.positions[i] = leafIndex;\n _setNode(self, leafIndex, newLeaves[i], 0);\n unchecked {\n ++i;\n }\n }\n return oldLeaves;\n }\n\n /// @dev Updates many leaves and re-hashes their paths to the root in one bottom-up pass, reading\n /// every sibling straight from storage — no merkle proof and no caller-supplied oldLeaves. Unlike\n /// updating each leaf on its own, this folds all paths together level by level, so a node shared\n /// by several updated paths is hashed exactly once.\n /// @param self: A storage reference to the 'FatIMTData' struct.\n /// @param newLeaves: The new values to write (parallel to leafIndexes).\n /// @param leafIndexes: The indexes of the leaves to update; must be strictly ascending.\n /// @return newRoot The new root after all updates.\n /// @return oldLeaves The values the leaves held before the update (for the event).\n /// @notice Reverts with WrongMultiProof on an empty batch, length mismatch, or non-ascending\n /// indexes, or LeafDoesNotExist if any index is out of range.\n function _updateMany(\n FatIMTData storage self,\n uint256[] calldata newLeaves,\n uint256[] calldata leafIndexes,\n function(uint256[2] memory) view returns (uint256) hasher\n ) internal returns (uint256, uint256[] memory) {\n uint256 leafCount = newLeaves.length;\n if (leafCount == 0 || leafCount != leafIndexes.length) {\n revert WrongMultiProof();\n }\n // init check moved to the Event layer (folded into the treeId read the event already does)\n\n uint256 treeSize = self.size;\n\n // Known nodes for the current level. Seeded with the new leaves at their indexes; the fold\n // rewrites parents into the low slots of these arrays each level.\n MultiProofLevel memory lvl = MultiProofLevel(new uint256[](leafCount), new uint256[](leafCount));\n uint256[] memory oldLeaves = _seedUpdateMany(self, newLeaves, leafIndexes, lvl, treeSize);\n\n UpdateManyLevel memory lvlPos = UpdateManyLevel(leafCount, treeSize - 1, 0);\n uint256 treeDepth = self.depth;\n for (lvlPos.level = 0; lvlPos.level < treeDepth; ) {\n // note: _updateManyLevel does ++lvlPos.level (this to safe on stack size)\n (lvl, lvlPos) = _updateManyLevel(self, lvl, lvlPos, hasher);\n }\n\n // paths all converged to the single top node; return it with the pre-update leaves\n return (lvl.nodes[0], oldLeaves);\n }\n\n /// @dev Retrieves the root of the tree from the 'nodes' mapping using the\n /// current tree depth. The root is the single node at the top level.\n /// @param self: A storage reference to the 'FatIMTData' struct.\n /// @return The root hash of the tree.\n function _root(FatIMTData storage self) internal view returns (uint256) {\n return self.nodes[self.depth][0];\n }\n}\n\n// @notes contract size limit work around: use _hashMultiProofLevel for both proofManyToRoot as updateMany\n// same with plain update\n// _hashMultiProofLevel uses 2 arrays for tracking nodes. currentLevel and nextLevel. You can prob just do it in 1\n// same for insertMany probably, but that is vivians code so i would rather keep it as similar as possible\n// and ofc we can just split into multiple contracts that export these internal functions. example move verify functions\n// outside of FatIMTPoseidon2WriteEvent\n\n// old unused code\n// this is not used because it only adds to contract size and gas of these functions.\n// it does read easier and more consistently with the other implementation\n//------------ update and proofToRoot written with hashLevel pattern like updateMany and proofManyToRoot -------------\n// /// @dev Updates the value of an existing leaf and recalculates hashes\n// /// to maintain tree integrity.\n// /// @param self: A storage reference to the 'FatIMTData' struct.\n// /// @param oldLeaf: The value of the leaf that is to be updated.\n// /// @param newLeaf: The new value that will replace the oldLeaf in the tree.\n// /// @param leafIndex: The index of the leaf to be updated.\n// /// @param proofSiblings: An array of sibling nodes that are necessary to recalculate the path to the root.\n// /// @return The new hash of the updated node after the leaf has been updated.\n// /// @notice Requires collision-resistant hashing: `if (self.sideNodes[level] == oldRoot)` identifies\n// /// which sideNode to refresh by hash equality,\n// /// so a collision between two distinct subtree roots would corrupt tree state silently.\n// /// @notice Contracts using this function with snark based hash functions,\n// /// need to check that the old and newLeaf and proofSiblings are within the snark scalar field.\n// function _update(\n// FatIMTData storage self,\n// uint256 oldLeaf,\n// uint256 newLeaf,\n// uint256 leafIndex,\n// uint256[] calldata proofSiblings,\n// function(uint256[2] memory) view returns (uint256) hasher\n// ) internal returns (uint256) {\n// if (_isInitialized(self) == false) {\n// revert NotInitialized();\n// }\n// // Cache tree depth to optimize gas\n// uint256 treeDepth = self.depth;\n// if (proofSiblings.length > treeDepth) {\n// revert WrongSiblingNodes();\n// }\n\n// uint256 treeSize = self.size;\n\n// // 2 vars to store intermediate hashes, to hash up to oldRoot and newRoot\n// uint256 newNode = newLeaf;\n// uint256 oldNode = oldLeaf;\n\n// ProofLevelPositions memory oldLevelPos = ProofLevelPositions(\n// leafIndex, // nodeIndex\n// treeSize - 1, // edgeIndex\n// treeSize, // nextInsertIndex\n// 0, // proofSiblingReadIndex\n// 0, // newSideNode\n// false // isNewSideNode\n// );\n// ProofLevelPositions memory newLevelPos = ProofLevelPositions(\n// leafIndex, // nodeIndex\n// treeSize - 1, // edgeIndex\n// treeSize, // nextInsertIndex\n// 0, // proofSiblingReadIndex\n// 0, // newSideNode\n// false // isNewSideNode\n// );\n// for (uint256 level = 0; level < treeDepth; ) {\n// // oldNode is just inclusion proof, so trackSideNodes=false, and we will use the same positions for newNode\n// // so trackPositions=false\n// (oldNode, oldLevelPos) = _hashProofLevel(oldNode, oldLevelPos, proofSiblings, hasher);\n// (newNode, newLevelPos) = _hashProofLevel(newNode, newLevelPos, proofSiblings, hasher);\n// if (newLevelPos.isNewSideNode) {\n// self.sideNodes[level] = newLevelPos.newSideNode;\n// }\n// unchecked {\n// ++level;\n// }\n// }\n\n// if (oldNode != _root(self)) {\n// revert WrongSiblingNodes();\n// }\n\n// self.sideNodes[treeDepth] = newNode;\n\n// return newNode;\n// }\n\n// struct ProofLevelPositions {\n// uint256 nodeIndex;\n// uint256 edgeIndex;\n// uint256 nextInsertIndex;\n// uint256 siblingIndex;\n// uint256 newSideNode;\n// bool isNewSideNode;\n// }\n\n// function _hashProofLevel(\n// uint256 node,\n// ProofLevelPositions memory levelPos,\n// uint256[] calldata proofSiblings,\n// function(uint256[2] memory) view returns (uint256) hasher\n// ) internal view returns (uint256, ProofLevelPositions memory) {\n// // The sideNode at this level is the node at position nextInsertIndex - 1, and only when this level\n// // is live (nextInsertIndex is odd). For a single-leaf update the one node we recompute (`node`, at\n// // position nodeIndex) is that sideNode exactly when nodeIndex == nextInsertIndex - 1. Write the result\n// // into the struct so the caller sees it; reset the flag each level since `levelPos` is reused.\n// if (levelPos.nextInsertIndex & 1 == 1 && (levelPos.nextInsertIndex - 1) == levelPos.nodeIndex) {\n// levelPos.newSideNode = node;\n// levelPos.isNewSideNode = true;\n// } else {\n// levelPos.isNewSideNode = false;\n// }\n// if (levelPos.nodeIndex & 1 == 1) {\n// node = hasher([proofSiblings[levelPos.siblingIndex], node]);\n// unchecked {\n// ++levelPos.siblingIndex;\n// }\n// } else {\n// // make sure node index is not at the edge @TODO explain\n// if (levelPos.nodeIndex != levelPos.edgeIndex) {\n// node = hasher([node, proofSiblings[levelPos.siblingIndex]]);\n\n// unchecked {\n// ++levelPos.siblingIndex;\n// }\n// }\n// }\n\n// levelPos.nodeIndex >>= 1;\n// levelPos.edgeIndex >>= 1;\n// levelPos.nextInsertIndex >>= 1;\n\n// return (node, levelPos);\n// }\n\n// /// @dev Hashes merkle proof and returns the root the leaf belongs to\n// /// @param leafIndex: The leaf to proof inclusion of\n// /// @param leafIndex: The index of the leaf within the tree.\n// /// @param proofSiblings: The sibling nodes along the path from the leaf to the root.\n// /// @return The root obtained from hashing the leaf with the provided siblings.\n// /// @notice Contracts using this function with snark based hash functions,\n// /// need to check that the leaf and proofSiblings are within the snark scalar field.\n// function _proofToRoot(\n// uint256 treeDepth,\n// uint256 treeSize,\n// uint256 leaf,\n// uint256 leafIndex,\n// uint256[] calldata proofSiblings,\n// function(uint256[2] memory) view returns (uint256) hasher\n// ) internal view returns (uint256) {\n// if (treeSize == 0) {\n// revert TreeEmpty();\n// }\n\n// uint256 node = leaf;\n// ProofLevelPositions memory levelPos = ProofLevelPositions(\n// leafIndex, // nodeIndex\n// // index of the very last leaf in the tree\n// // tracking this index up the tree, follows the indexes of the nodes in self.sidNodes\n// treeSize - 1, // edgeIndex\n// // index of the next insert in the tree, tracking this up to tree to determine\n// // what sideNode is needed to store\n// treeSize, // nextInsertIndex\n// // because leanIMT is not balanced proofSiblings.length can be smaller then tree depth\n// // we cant just use level so we separately track those 2\n// 0, // proofSiblingReadIndex\n// 0, // newSideNode\n// false // isNewSideNode\n// );\n// for (uint256 level = 0; level < treeDepth; ) {\n// // no need for sideNodes so trackSideNodes=false\n// (node, levelPos) = _hashProofLevel(node, levelPos, proofSiblings, hasher);\n\n// unchecked {\n// ++level;\n// }\n// }\n// return node;\n// }\n//---------------------------------------------------------------------------------------------------------------------\n"
195
+ },
196
+ "npm/@warptoad/fat-imt.sol@0.0.11/InternalFatIMTEvent.sol": {
197
+ "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.4;\n\nimport {InternalFatIMTCore, FatIMTData as FatIMTDataEvent, MultiProof, TreeEmpty} from \"./InternalFatIMTCore.sol\";\nimport {IIMTEvents} from \"./interfaces/IIMTEvents.sol\";\nimport {_emitUpdatedMany, _requireInField, _requireAllInField} from \"./FatIMTUtils.sol\";\n\nerror EndIndexOutOfRange();\nerror LevelOutOfRange();\nerror NotInitialized();\nerror AlreadyInitialized();\n\nlibrary InternalFatIMTEvent {\n function _reset(FatIMTDataEvent storage self) internal {\n uint256 id = self.treeId;\n emit IIMTEvents.NewRoot(id, 0, 0);\n InternalFatIMTCore._reset(self);\n }\n\n /// @dev Checks whether the tree has been initialized.\n function _isInitialized(FatIMTDataEvent storage self) internal view returns (bool) {\n return self.treeId != 0;\n }\n\n /// @dev Initializes the tree by assigning it a non-zero `treeId` derived from its storage slot.\n /// `self.treeId` stores `self.slot + 1` so upgradeable contracts that move the slot keep their id.\n function _init(FatIMTDataEvent storage self) internal returns (uint256) {\n if (_isInitialized(self)) {\n revert AlreadyInitialized();\n }\n uint256 slot;\n assembly {\n slot := self.slot\n }\n uint256 id = slot + 1;\n self.treeId = id;\n emit IIMTEvents.NewTree(id);\n emit IIMTEvents.NewRoot(id, 0, 0);\n return id;\n }\n\n /// helper function for clients to retrieve nodes in a batch\n /// @notice set level 0 to get the leaves\n /// @param self: A storage reference to the 'FatIMTDataEvent' struct.\n /// @param firstIndex: first node index to get (inclusive)\n /// @param endIndex: last node index to stop retrieving at (exclusive)\n /// @param level: the tree level to read from (0 == leaves)\n function _getNodes(\n FatIMTDataEvent storage self,\n uint256 firstIndex,\n uint256 endIndex,\n uint256 level\n ) internal view returns (uint256[] memory) {\n if (level > self.depth) {\n revert LevelOutOfRange();\n }\n // number of nodes at this level = ceil(size / 2**level); the rightmost may be a dangling node\n uint256 nodeCountAtLevel = (self.size + (1 << level) - 1) >> level;\n if (endIndex > nodeCountAtLevel) {\n revert EndIndexOutOfRange();\n }\n uint256[] memory nodes = new uint256[](endIndex - firstIndex);\n for (uint256 i = 0; i < nodes.length; i++) {\n nodes[i] = self.nodes[level][firstIndex + i];\n }\n return nodes;\n }\n\n /// helper function for clients to retrieve the repeated-value hash cache in a batch\n /// @notice the cache is keyed by the repeated *value*, not by a position, so the range walks\n /// values `firstIndex` .. `endIndex - 1`; an uncached value reads back as 0\n /// @param self: A storage reference to the 'FatIMTData' struct.\n /// @param firstIndex: first value to look up (inclusive)\n /// @param endIndex: value to stop looking up at (exclusive)\n function _getRepeatedHashes(\n FatIMTDataEvent storage self,\n uint256 firstIndex,\n uint256 endIndex\n ) internal view returns (uint256[] memory) {\n uint256[] memory hashes = new uint256[](endIndex - firstIndex);\n for (uint256 i = 0; i < hashes.length; i++) {\n hashes[i] = self.repeatedHashCache[firstIndex + i];\n }\n return hashes;\n }\n\n function _insert(\n FatIMTDataEvent storage self,\n uint256 leaf,\n function(uint256[2] memory) view returns (uint256) hasher\n ) internal returns (uint256, uint256) {\n // update tree\n (uint256 newRoot, uint256 index) = InternalFatIMTCore._insert(self, leaf, hasher);\n // emit IIMTEvents.event\n uint256 treeId = self.treeId;\n if (treeId == 0) {\n revert NotInitialized();\n }\n emit IIMTEvents.NewLeaf(treeId, index, leaf);\n emit IIMTEvents.NewRoot(treeId, newRoot, self.size);\n return (newRoot, index);\n }\n\n function _insertBN254(\n FatIMTDataEvent storage self,\n uint256 leaf,\n function(uint256[2] memory) view returns (uint256) hasher\n ) internal returns (uint256, uint256) {\n // field check\n _requireInField(leaf);\n // update tree\n (uint256 newRoot, uint256 index) = InternalFatIMTCore._insert(self, leaf, hasher);\n // emit IIMTEvents.event\n uint256 treeId = self.treeId;\n if (treeId == 0) {\n revert NotInitialized();\n }\n emit IIMTEvents.NewLeaf(treeId, index, leaf);\n emit IIMTEvents.NewRoot(treeId, newRoot, self.size);\n return (newRoot, index);\n }\n\n function _insertMany(\n FatIMTDataEvent storage self,\n uint256[] calldata leaves,\n function(uint256[2] memory) view returns (uint256) hasher\n ) internal returns (uint256, uint256, uint256) {\n // update tree (Core now owns start/next, like _insertManyRepeated)\n (uint256 newRoot, uint256 startIndex, uint256 nextIndex) = InternalFatIMTCore._insertMany(self, leaves, hasher);\n\n // emit IIMTEvents.events\n uint256 treeId = self.treeId;\n if (treeId == 0) {\n revert NotInitialized();\n }\n for (uint256 i = 0; i < leaves.length; ) {\n emit IIMTEvents.NewLeaf(treeId, startIndex + i, leaves[i]);\n unchecked {\n ++i;\n }\n }\n emit IIMTEvents.NewRoot(treeId, newRoot, nextIndex);\n return (newRoot, startIndex, nextIndex);\n }\n\n function _insertManyBN254(\n FatIMTDataEvent storage self,\n uint256[] calldata leaves,\n function(uint256[2] memory) view returns (uint256) hasher\n ) internal returns (uint256, uint256, uint256) {\n // check all leaves are in field before mutating the tree\n _requireAllInField(leaves);\n\n // update tree (Core now owns start/next, like _insertManyRepeated)\n (uint256 newRoot, uint256 startIndex, uint256 nextIndex) = InternalFatIMTCore._insertMany(self, leaves, hasher);\n\n // emit IIMTEvents.events\n uint256 treeId = self.treeId;\n if (treeId == 0) {\n revert NotInitialized();\n }\n for (uint256 i = 0; i < leaves.length; ) {\n emit IIMTEvents.NewLeaf(treeId, startIndex + i, leaves[i]);\n unchecked {\n ++i;\n }\n }\n emit IIMTEvents.NewRoot(treeId, newRoot, nextIndex);\n return (newRoot, startIndex, nextIndex);\n }\n\n function _insertManyRepeated(\n FatIMTDataEvent storage self,\n uint256 value,\n uint256 amount,\n function(uint256[2] memory) view returns (uint256) hasher\n ) internal returns (uint256, uint256, uint256) {\n // update tree\n (uint256 newRoot, uint256 startIndex, uint256 nextIndex) = InternalFatIMTCore._insertManyRepeated(\n self,\n value,\n amount,\n hasher\n );\n // emit IIMTEvents.events. fat-imt stores every node anyway, so a NewLeaf per leaf costs it nothing extra.\n // (skinny keeps only RepeatedLeafs here, since there per-leaf events would wreck its scaling.)\n uint256 treeId = self.treeId;\n if (treeId == 0) {\n revert NotInitialized();\n }\n for (uint256 i = 0; i < amount; ) {\n emit IIMTEvents.NewLeaf(treeId, startIndex + i, value);\n unchecked {\n ++i;\n }\n }\n emit IIMTEvents.RepeatedLeafs(treeId, startIndex, nextIndex, value);\n emit IIMTEvents.NewRoot(treeId, newRoot, nextIndex);\n return (newRoot, startIndex, nextIndex);\n }\n\n function _insertManyRepeatedBN254(\n FatIMTDataEvent storage self,\n uint256 value,\n uint256 amount,\n function(uint256[2] memory) view returns (uint256) hasher\n ) internal returns (uint256, uint256, uint256) {\n // check\n _requireInField(value);\n // update tree\n (uint256 newRoot, uint256 startIndex, uint256 nextIndex) = InternalFatIMTCore._insertManyRepeated(\n self,\n value,\n amount,\n hasher\n );\n // emit IIMTEvents.events. fat-imt stores every node anyway, so a NewLeaf per leaf costs it nothing extra.\n // (skinny keeps only RepeatedLeafs here, since there per-leaf events would wreck its scaling.)\n uint256 treeId = self.treeId;\n if (treeId == 0) {\n revert NotInitialized();\n }\n for (uint256 i = 0; i < amount; ) {\n emit IIMTEvents.NewLeaf(treeId, startIndex + i, value);\n unchecked {\n ++i;\n }\n }\n emit IIMTEvents.RepeatedLeafs(treeId, startIndex, nextIndex, value);\n emit IIMTEvents.NewRoot(treeId, newRoot, nextIndex);\n return (newRoot, startIndex, nextIndex);\n }\n\n function _precomputeRepeatedCache(\n FatIMTDataEvent storage self,\n uint256 value,\n uint256 upToLevel,\n function(uint256[2] memory) view returns (uint256) hasher\n ) internal {\n // precompute emits no event, so it never reads treeId; guard init explicitly (rare op)\n if (self.treeId == 0) {\n revert NotInitialized();\n }\n // update cache\n InternalFatIMTCore._precomputeRepeatedCache(self, value, upToLevel, hasher);\n }\n\n function _precomputeRepeatedCacheBN254(\n FatIMTDataEvent storage self,\n uint256 value,\n uint256 upToLevel,\n function(uint256[2] memory) view returns (uint256) hasher\n ) internal {\n // precompute emits no event, so it never reads treeId; guard init explicitly (rare op)\n if (self.treeId == 0) {\n revert NotInitialized();\n }\n // check\n _requireInField(value);\n // update cache\n InternalFatIMTCore._precomputeRepeatedCache(self, value, upToLevel, hasher);\n }\n\n function _update(\n FatIMTDataEvent storage self,\n uint256 newLeaf,\n uint256 leafIndex,\n function(uint256[2] memory) view returns (uint256) hasher\n ) internal returns (uint256, uint256) {\n // update tree\n (uint256 newRoot, uint256 oldLeaf) = InternalFatIMTCore._update(self, newLeaf, leafIndex, hasher);\n // emit IIMTEvents.event\n uint256 treeId = self.treeId;\n if (treeId == 0) {\n revert NotInitialized();\n }\n emit IIMTEvents.UpdatedLeaf(treeId, leafIndex, newLeaf, oldLeaf);\n emit IIMTEvents.NewRoot(treeId, newRoot, self.size);\n return (newRoot, oldLeaf);\n }\n\n function _updateBN254(\n FatIMTDataEvent storage self,\n uint256 newLeaf,\n uint256 leafIndex,\n function(uint256[2] memory) view returns (uint256) hasher\n ) internal returns (uint256, uint256) {\n // check\n _requireInField(newLeaf);\n // update tree\n (uint256 newRoot, uint256 oldLeaf) = InternalFatIMTCore._update(self, newLeaf, leafIndex, hasher);\n // emit IIMTEvents.event\n uint256 treeId = self.treeId;\n if (treeId == 0) {\n revert NotInitialized();\n }\n emit IIMTEvents.UpdatedLeaf(treeId, leafIndex, newLeaf, oldLeaf);\n emit IIMTEvents.NewRoot(treeId, newRoot, self.size);\n return (newRoot, oldLeaf);\n }\n\n function _updateMany(\n FatIMTDataEvent storage self,\n uint256[] calldata newLeaves,\n uint256[] calldata leafIndexes,\n function(uint256[2] memory) view returns (uint256) hasher\n ) internal returns (uint256, uint256[] memory) {\n // check: guards the edgeIndex (size - 1) underflow in the core on an empty tree\n if (self.size == 0) {\n revert TreeEmpty();\n }\n\n // update tree\n (uint256 newRoot, uint256[] memory oldLeaves) = InternalFatIMTCore._updateMany(\n self,\n newLeaves,\n leafIndexes,\n hasher\n );\n // emit IIMTEvents.event\n // no tree.id == 0 check here, self.size == 0 already does that, also stack limit is too tight\n _emitUpdatedMany(self.treeId, leafIndexes, oldLeaves, newLeaves);\n emit IIMTEvents.NewRoot(self.treeId, newRoot, self.size);\n return (newRoot, oldLeaves);\n }\n\n function _updateManyBN254(\n FatIMTDataEvent storage self,\n uint256[] calldata newLeaves,\n uint256[] calldata leafIndexes,\n function(uint256[2] memory) view returns (uint256) hasher\n ) internal returns (uint256, uint256[] memory) {\n // check: guards the edgeIndex (size - 1) underflow in the core on an empty tree\n if (self.size == 0) {\n revert TreeEmpty();\n }\n _requireAllInField(newLeaves);\n\n // update tree\n (uint256 newRoot, uint256[] memory oldLeaves) = InternalFatIMTCore._updateMany(\n self,\n newLeaves,\n leafIndexes,\n hasher\n );\n // emit IIMTEvents.event\n // no tree.id == 0 check here, self.size == 0 already does that, also stack limit is too tight\n _emitUpdatedMany(self.treeId, leafIndexes, oldLeaves, newLeaves);\n emit IIMTEvents.NewRoot(self.treeId, newRoot, self.size);\n return (newRoot, oldLeaves);\n }\n\n function _root(FatIMTDataEvent storage self) internal view returns (uint256) {\n return InternalFatIMTCore._root(self);\n }\n\n function _proofToRoot(\n uint256 treeDepth,\n uint256 treeSize,\n uint256 leaf,\n uint256 leafIndex,\n uint256[] calldata proofSiblings,\n function(uint256[2] memory) view returns (uint256) hasher\n ) internal view returns (uint256) {\n // verify\n return InternalFatIMTCore._proofToRoot(treeDepth, treeSize, leaf, leafIndex, proofSiblings, hasher);\n }\n\n function _proofToRootBN254(\n uint256 treeDepth,\n uint256 treeSize,\n uint256 leaf,\n uint256 leafIndex,\n uint256[] calldata proofSiblings,\n function(uint256[2] memory) view returns (uint256) hasher\n ) internal view returns (uint256) {\n // check\n _requireInField(leaf);\n _requireAllInField(proofSiblings);\n // verify\n return InternalFatIMTCore._proofToRoot(treeDepth, treeSize, leaf, leafIndex, proofSiblings, hasher);\n }\n\n function _proofManyToRoot(\n uint256 treeDepth,\n uint256 treeSize,\n uint256[] calldata leaves,\n uint256[] calldata leafIndexes,\n uint256[] calldata proofSiblings,\n function(uint256[2] memory) view returns (uint256) hasher\n ) internal view returns (uint256) {\n // takes treeSize (like _proofToRoot); Core's MultiProof works off edgeIndex == treeSize - 1\n if (treeSize == 0) {\n revert TreeEmpty();\n }\n // verify\n return\n InternalFatIMTCore._proofManyToRoot(\n leaves,\n MultiProof(treeDepth, treeSize - 1, leafIndexes, proofSiblings),\n hasher\n );\n }\n\n function _proofManyToRootBN254(\n uint256 treeDepth,\n uint256 treeSize,\n uint256[] calldata leaves,\n uint256[] calldata leafIndexes,\n uint256[] calldata proofSiblings,\n function(uint256[2] memory) view returns (uint256) hasher\n ) internal view returns (uint256) {\n // check\n _requireAllInField(leaves);\n _requireAllInField(proofSiblings);\n // takes treeSize (like _proofToRoot); Core's MultiProof works off edgeIndex == treeSize - 1\n if (treeSize == 0) {\n revert TreeEmpty();\n }\n // verify\n return\n InternalFatIMTCore._proofManyToRoot(\n leaves,\n MultiProof(treeDepth, treeSize - 1, leafIndexes, proofSiblings),\n hasher\n );\n }\n}\n"
198
+ },
199
+ "npm/@warptoad/fat-imt.sol@0.0.11/InternalFatIMTStorage.sol": {
200
+ "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.4;\n\nimport {InternalFatIMTEvent, FatIMTDataEvent} from \"./InternalFatIMTEvent.sol\";\nimport {_emitUpdatedMany, _requireInField, _requireAllInField} from \"./FatIMTUtils.sol\";\n\n// added storage of the leaves to allow syncing with full nodes for leaves older then 1 year\nstruct FatIMTDataStorage {\n // arrays cost more but store in consecutive slots which allows for usage of debug_storageRangeAt\n // to read this extremely fast\n uint256[] leaves;\n FatIMTDataEvent treeData;\n}\n\nlibrary InternalFatIMTStorage {\n function _reset(FatIMTDataStorage storage self) internal {\n // the Storage variant also stores leaves in a pushed array, so it must be cleared here;\n // InternalFatIMTEvent._reset only zeroes size/depth in the core.\n delete self.leaves;\n InternalFatIMTEvent._reset(self.treeData);\n }\n\n /// helper function for clients that don't have debug_storageRangeAt\n /// @param self: A storage reference to the 'FatIMTDataStorage' struct.\n /// @param firstIndex: first leaf index to get (inclusive)\n /// @param endIndex: last leaf index to stop retrieving at (exclusive)\n function _getLeaves(\n FatIMTDataStorage storage self,\n uint256 firstIndex,\n uint256 endIndex\n ) internal view returns (uint256[] memory) {\n uint256[] memory leaves = new uint256[](endIndex - firstIndex);\n for (uint256 i = 0; i < leaves.length; i++) {\n leaves[i] = self.leaves[firstIndex + i];\n }\n return leaves;\n }\n\n function _getNodes(\n FatIMTDataStorage storage self,\n uint256 firstIndex,\n uint256 endIndex,\n uint256 level\n ) internal view returns (uint256[] memory) {\n return InternalFatIMTEvent._getNodes(self.treeData, firstIndex, endIndex, level);\n }\n\n function _getRepeatedHashes(\n FatIMTDataStorage storage self,\n uint256 firstIndex,\n uint256 endIndex\n ) internal view returns (uint256[] memory) {\n return InternalFatIMTEvent._getRepeatedHashes(self.treeData, firstIndex, endIndex);\n }\n\n function _init(FatIMTDataStorage storage self) internal returns (uint256) {\n return InternalFatIMTEvent._init(self.treeData);\n }\n\n function _insert(\n FatIMTDataStorage storage self,\n uint256 leaf,\n function(uint256[2] memory) view returns (uint256) hasher\n ) internal returns (uint256, uint256) {\n self.leaves.push(leaf);\n return InternalFatIMTEvent._insert(self.treeData, leaf, hasher);\n }\n\n function _insertBN254(\n FatIMTDataStorage storage self,\n uint256 leaf,\n function(uint256[2] memory) view returns (uint256) hasher\n ) internal returns (uint256, uint256) {\n self.leaves.push(leaf);\n return InternalFatIMTEvent._insertBN254(self.treeData, leaf, hasher);\n }\n\n function _insertMany(\n FatIMTDataStorage storage self,\n uint256[] calldata leaves,\n function(uint256[2] memory) view returns (uint256) hasher\n ) internal returns (uint256, uint256, uint256) {\n for (uint256 i = 0; i < leaves.length; i++) {\n self.leaves.push(leaves[i]);\n }\n return InternalFatIMTEvent._insertMany(self.treeData, leaves, hasher);\n }\n\n function _insertManyBN254(\n FatIMTDataStorage storage self,\n uint256[] calldata leaves,\n function(uint256[2] memory) view returns (uint256) hasher\n ) internal returns (uint256, uint256, uint256) {\n for (uint256 i = 0; i < leaves.length; i++) {\n self.leaves.push(leaves[i]);\n }\n return InternalFatIMTEvent._insertManyBN254(self.treeData, leaves, hasher);\n }\n\n function _insertManyRepeated(\n FatIMTDataStorage storage self,\n uint256 value,\n uint256 amount,\n function(uint256[2] memory) view returns (uint256) hasher\n ) internal returns (uint256, uint256, uint256) {\n // leaves are stored here; NewLeaf/RepeatedLeafs events are emitted by the Event layer.\n for (uint256 i = 0; i < amount; i++) {\n self.leaves.push(value);\n }\n return InternalFatIMTEvent._insertManyRepeated(self.treeData, value, amount, hasher);\n }\n\n function _insertManyRepeatedBN254(\n FatIMTDataStorage storage self,\n uint256 value,\n uint256 amount,\n function(uint256[2] memory) view returns (uint256) hasher\n ) internal returns (uint256, uint256, uint256) {\n // leaves are stored here; NewLeaf/RepeatedLeafs events are emitted by the Event layer.\n for (uint256 i = 0; i < amount; i++) {\n self.leaves.push(value);\n }\n return InternalFatIMTEvent._insertManyRepeatedBN254(self.treeData, value, amount, hasher);\n }\n\n function _precomputeRepeatedCache(\n FatIMTDataStorage storage self,\n uint256 value,\n uint256 upToLevel,\n function(uint256[2] memory) view returns (uint256) hasher\n ) internal {\n return InternalFatIMTEvent._precomputeRepeatedCache(self.treeData, value, upToLevel, hasher);\n }\n\n function _precomputeRepeatedCacheBN254(\n FatIMTDataStorage storage self,\n uint256 value,\n uint256 upToLevel,\n function(uint256[2] memory) view returns (uint256) hasher\n ) internal {\n return InternalFatIMTEvent._precomputeRepeatedCacheBN254(self.treeData, value, upToLevel, hasher);\n }\n\n function _update(\n FatIMTDataStorage storage self,\n uint256 newLeaf,\n uint256 leafIndex,\n function(uint256[2] memory) view returns (uint256) hasher\n ) internal returns (uint256, uint256) {\n self.leaves[leafIndex] = newLeaf;\n return InternalFatIMTEvent._update(self.treeData, newLeaf, leafIndex, hasher);\n }\n\n function _updateBN254(\n FatIMTDataStorage storage self,\n uint256 newLeaf,\n uint256 leafIndex,\n function(uint256[2] memory) view returns (uint256) hasher\n ) internal returns (uint256, uint256) {\n self.leaves[leafIndex] = newLeaf;\n return InternalFatIMTEvent._updateBN254(self.treeData, newLeaf, leafIndex, hasher);\n }\n\n function _updateMany(\n FatIMTDataStorage storage self,\n uint256[] calldata newLeaves,\n uint256[] calldata leafIndexes,\n function(uint256[2] memory) view returns (uint256) hasher\n ) internal returns (uint256, uint256[] memory) {\n for (uint256 i = 0; i < newLeaves.length; i++) {\n self.leaves[leafIndexes[i]] = newLeaves[i];\n }\n return InternalFatIMTEvent._updateMany(self.treeData, newLeaves, leafIndexes, hasher);\n }\n\n function _updateManyBN254(\n FatIMTDataStorage storage self,\n uint256[] calldata newLeaves,\n uint256[] calldata leafIndexes,\n function(uint256[2] memory) view returns (uint256) hasher\n ) internal returns (uint256, uint256[] memory) {\n for (uint256 i = 0; i < newLeaves.length; i++) {\n self.leaves[leafIndexes[i]] = newLeaves[i];\n }\n return InternalFatIMTEvent._updateManyBN254(self.treeData, newLeaves, leafIndexes, hasher);\n }\n\n function _root(FatIMTDataStorage storage self) internal view returns (uint256) {\n return InternalFatIMTEvent._root(self.treeData);\n }\n\n function _proofToRoot(\n uint256 treeDepth,\n uint256 treeSize,\n uint256 leaf,\n uint256 leafIndex,\n uint256[] calldata proofSiblings,\n function(uint256[2] memory) view returns (uint256) hasher\n ) internal view returns (uint256) {\n return InternalFatIMTEvent._proofToRoot(treeDepth, treeSize, leaf, leafIndex, proofSiblings, hasher);\n }\n\n function _proofToRootBN254(\n uint256 treeDepth,\n uint256 treeSize,\n uint256 leaf,\n uint256 leafIndex,\n uint256[] calldata proofSiblings,\n function(uint256[2] memory) view returns (uint256) hasher\n ) internal view returns (uint256) {\n return InternalFatIMTEvent._proofToRootBN254(treeDepth, treeSize, leaf, leafIndex, proofSiblings, hasher);\n }\n\n function _proofManyToRoot(\n uint256 treeDepth,\n uint256 treeSize,\n uint256[] calldata leaves,\n uint256[] calldata leafIndexes,\n uint256[] calldata proofSiblings,\n function(uint256[2] memory) view returns (uint256) hasher\n ) internal view returns (uint256) {\n return InternalFatIMTEvent._proofManyToRoot(treeDepth, treeSize, leaves, leafIndexes, proofSiblings, hasher);\n }\n\n function _proofManyToRootBN254(\n uint256 treeDepth,\n uint256 treeSize,\n uint256[] calldata leaves,\n uint256[] calldata leafIndexes,\n uint256[] calldata proofSiblings,\n function(uint256[2] memory) view returns (uint256) hasher\n ) internal view returns (uint256) {\n return\n InternalFatIMTEvent._proofManyToRootBN254(treeDepth, treeSize, leaves, leafIndexes, proofSiblings, hasher);\n }\n}\n"
201
+ },
202
+ "npm/@warptoad/fat-imt.sol@0.0.11/poseidon2/FatIMTPoseidon2Read.sol": {
203
+ "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.4;\n\nimport {LibPoseidon2Yul} from \"poseidon2-evm/src/bn254/yul/LibPoseidon2Yul.sol\";\n\nimport {InternalFatIMTEvent, FatIMTDataEvent} from \"../InternalFatIMTEvent.sol\";\nimport {TreeEmpty} from \"../InternalFatIMTCore.sol\";\nimport {InternalFatIMTStorage, FatIMTDataStorage} from \"../InternalFatIMTStorage.sol\";\n\n/// @title FatIMTPoseidon2Read\n/// @notice Stateless proof verification (`proofToRoot` / `proofManyToRoot`) split out of\n/// `FatIMTPoseidon2WriteEvent` and `FatIMTPoseidon2WriteStorage` to keep those libraries under the\n/// EIP-170 contract size limit. Both functions take the whole proof as parameters and touch no\n/// storage, so a single library serves the plain and full-node trees alike.\nlibrary FatIMTPoseidon2Read {\n function hasher(uint256[2] memory leaves) public pure returns (uint256) {\n return LibPoseidon2Yul.hash_2(leaves[0], leaves[1]);\n }\n\n function root(FatIMTDataEvent storage self) public view returns (uint256) {\n return InternalFatIMTEvent._root(self);\n }\n\n /// @notice Batch node getter. Reads the `nodes` mapping, which lives in `FatIMTDataEvent` for both the\n /// plain and full-node trees — a full-node caller passes its `.treeData`. Hosted here (rather\n /// than in the two wrapper libraries) to keep them under the EIP-170 size limit. set level 0 to\n /// get the leaves.\n function getNodes(\n FatIMTDataEvent storage self,\n uint256 firstIndex,\n uint256 endIndex,\n uint256 level\n ) public view returns (uint256[] memory) {\n return InternalFatIMTEvent._getNodes(self, firstIndex, endIndex, level);\n }\n\n /// @notice Leaf getter for the plain/archive tree: its leaves live in the `nodes` mapping at\n /// level 0, so this is `getNodes(self, ..., 0)`.\n function getLeaves(\n FatIMTDataEvent storage self,\n uint256 firstIndex,\n uint256 endIndex\n ) public view returns (uint256[] memory) {\n return InternalFatIMTEvent._getNodes(self, firstIndex, endIndex, 0);\n }\n\n /// @notice Leaf getter for the full-node tree: reads its dedicated `leaves` array (consecutive\n /// storage slots, fast via debug_storageRangeAt). Pass the whole full-node struct, not `.treeData`.\n function getLeaves(\n FatIMTDataStorage storage self,\n uint256 firstIndex,\n uint256 endIndex\n ) public view returns (uint256[] memory) {\n return InternalFatIMTStorage._getLeaves(self, firstIndex, endIndex);\n }\n\n function proofToRootBN254(\n uint256 treeDepth,\n uint256 treeSize,\n uint256 leaf,\n uint256 leafIndex,\n uint256[] calldata proofSiblings\n ) public view returns (uint256) {\n return InternalFatIMTEvent._proofToRootBN254(treeDepth, treeSize, leaf, leafIndex, proofSiblings, hasher);\n }\n\n function proofManyToRootBN254(\n uint256 treeDepth,\n uint256 treeSize,\n uint256[] calldata leaves,\n uint256[] calldata leafIndexes,\n uint256[] calldata proofSiblings\n ) public view returns (uint256) {\n return\n InternalFatIMTEvent._proofManyToRootBN254(treeDepth, treeSize, leaves, leafIndexes, proofSiblings, hasher);\n }\n\n function verify(\n FatIMTDataEvent storage self,\n uint256 leaf,\n uint256 leafIndex,\n uint256[] calldata proofSiblings\n ) public view returns (bool) {\n if (self.size == 0) {\n revert TreeEmpty();\n }\n uint256 provenRoot = InternalFatIMTEvent._proofToRootBN254(\n self.depth,\n self.size,\n leaf,\n leafIndex,\n proofSiblings,\n hasher\n );\n uint256 currentRoot = InternalFatIMTEvent._root(self);\n return provenRoot == currentRoot;\n }\n\n function verifyMany(\n FatIMTDataEvent storage self,\n uint256[] calldata leaves,\n uint256[] calldata leafIndexes,\n uint256[] calldata proofSiblings\n ) public view returns (bool) {\n if (self.size == 0) {\n revert TreeEmpty();\n }\n uint256 provenRoot = InternalFatIMTEvent._proofManyToRootBN254(\n self.depth,\n self.size,\n leaves,\n leafIndexes,\n proofSiblings,\n hasher\n );\n uint256 currentRoot = InternalFatIMTEvent._root(self);\n return provenRoot == currentRoot;\n }\n}\n"
204
+ },
205
+ "npm/@warptoad/fat-imt.sol@0.0.11/poseidon2/FatIMTPoseidon2WriteEvent.sol": {
206
+ "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.4;\n\nimport {LibPoseidon2Yul} from \"poseidon2-evm/src/bn254/yul/LibPoseidon2Yul.sol\";\n\nimport {InternalFatIMTEvent, FatIMTDataEvent} from \"../InternalFatIMTEvent.sol\";\n\nlibrary FatIMTPoseidon2WriteEvent {\n function hasher(uint256[2] memory leaves) public pure returns (uint256) {\n return LibPoseidon2Yul.hash_2(leaves[0], leaves[1]);\n }\n\n function init(FatIMTDataEvent storage self) public returns (uint256) {\n return InternalFatIMTEvent._init(self);\n }\n\n function reset(FatIMTDataEvent storage self) internal {\n InternalFatIMTEvent._reset(self);\n }\n\n // getNodes and getLeaves both live in FatIMTPoseidon2Read to keep this library under the EIP-170 size limit.\n\n function insert(FatIMTDataEvent storage self, uint256 leaf) public returns (uint256, uint256) {\n return InternalFatIMTEvent._insertBN254(self, leaf, hasher);\n }\n\n function insertMany(\n FatIMTDataEvent storage self,\n uint256[] calldata leaves\n ) public returns (uint256, uint256, uint256) {\n return InternalFatIMTEvent._insertManyBN254(self, leaves, hasher);\n }\n\n function insertManyRepeated(\n FatIMTDataEvent storage self,\n uint256 value,\n uint256 amount\n ) public returns (uint256, uint256, uint256) {\n return InternalFatIMTEvent._insertManyRepeatedBN254(self, value, amount, hasher);\n }\n\n function precomputeRepeatedCache(FatIMTDataEvent storage self, uint256 value, uint256 upToLevel) internal {\n return InternalFatIMTEvent._precomputeRepeatedCacheBN254(self, value, upToLevel, hasher);\n }\n\n function update(\n FatIMTDataEvent storage self,\n uint256 newLeaf,\n uint256 leafIndex\n ) public returns (uint256, uint256) {\n return InternalFatIMTEvent._updateBN254(self, newLeaf, leafIndex, hasher);\n }\n\n function updateMany(\n FatIMTDataEvent storage self,\n uint256[] calldata newLeaves,\n uint256[] calldata leafIndexes\n ) public returns (uint256, uint256[] memory) {\n return InternalFatIMTEvent._updateManyBN254(self, newLeaves, leafIndexes, hasher);\n }\n}\n"
207
+ },
208
+ "npm/@warptoad/fat-imt.sol@0.0.11/poseidon2/FatIMTPoseidon2WriteStorage.sol": {
209
+ "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.4;\n\nimport {LibPoseidon2Yul} from \"poseidon2-evm/src/bn254/yul/LibPoseidon2Yul.sol\";\n\nimport {InternalFatIMTStorage, FatIMTDataStorage} from \"../InternalFatIMTStorage.sol\";\n\nlibrary FatIMTPoseidon2WriteStorage {\n function hasher(uint256[2] memory leaves) public pure returns (uint256) {\n return LibPoseidon2Yul.hash_2(leaves[0], leaves[1]);\n }\n\n function init(FatIMTDataStorage storage self) public returns (uint256) {\n return InternalFatIMTStorage._init(self);\n }\n\n function reset(FatIMTDataStorage storage self) internal {\n InternalFatIMTStorage._reset(self);\n }\n\n // getNodes and getLeaves both live in FatIMTPoseidon2Read to keep this library under the EIP-170\n // size limit (getNodes reads `.treeData`; getLeaves takes the whole full-node struct for `leaves`).\n\n function insert(FatIMTDataStorage storage self, uint256 leaf) public returns (uint256, uint256) {\n return InternalFatIMTStorage._insertBN254(self, leaf, hasher);\n }\n\n function insertMany(\n FatIMTDataStorage storage self,\n uint256[] calldata leaves\n ) public returns (uint256, uint256, uint256) {\n return InternalFatIMTStorage._insertManyBN254(self, leaves, hasher);\n }\n\n function insertManyRepeated(\n FatIMTDataStorage storage self,\n uint256 value,\n uint256 amount\n ) public returns (uint256, uint256, uint256) {\n return InternalFatIMTStorage._insertManyRepeatedBN254(self, value, amount, hasher);\n }\n\n function precomputeRepeatedCache(FatIMTDataStorage storage self, uint256 value, uint256 upToLevel) internal {\n return InternalFatIMTStorage._precomputeRepeatedCacheBN254(self, value, upToLevel, hasher);\n }\n\n function update(\n FatIMTDataStorage storage self,\n uint256 newLeaf,\n uint256 leafIndex\n ) public returns (uint256, uint256) {\n return InternalFatIMTStorage._updateBN254(self, newLeaf, leafIndex, hasher);\n }\n\n function updateMany(\n FatIMTDataStorage storage self,\n uint256[] calldata newLeaves,\n uint256[] calldata leafIndexes\n ) public returns (uint256, uint256[] memory) {\n return InternalFatIMTStorage._updateManyBN254(self, newLeaves, leafIndexes, hasher);\n }\n}\n"
210
+ },
211
+ "npm/@warptoad/skinny-imt.sol@0.0.11/Constants.sol": {
212
+ "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.4;\n\nuint256 constant SNARK_SCALAR_FIELD = 21888242871839275222246405745257275088548364400416034343698204186575808495617;\n"
213
+ },
214
+ "npm/@warptoad/skinny-imt.sol@0.0.11/interfaces/IIMTEvents.sol": {
215
+ "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.4;\n\ninterface IIMTEvents {\n // rename just leaf to newLeaf, so event abi is even easier to work with!\n event NewLeaf(uint256 indexed treeId, uint256 indexed index, uint256 indexed leaf);\n event UpdatedLeaf(uint256 indexed treeId, uint256 indexed index, uint256 indexed newLeaf, uint256 oldLeaf);\n event RepeatedLeafs(uint256 indexed treeId, uint256 indexed startIndex, uint256 nextIndex, uint256 indexed leaf);\n event NewTree(uint256 indexed treeId);\n event NewRoot(uint256 indexed treeId, uint256 indexed root, uint256 size);\n}\n"
216
+ },
217
+ "npm/@warptoad/skinny-imt.sol@0.0.11/interfaces/ISkinnyIMTReadableEvent.sol": {
218
+ "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.20;\n\nimport {IERC165} from \"@openzeppelin/contracts/utils/introspection/IERC165.sol\";\n\n/// @title ISkinnyIMTReadableEvent\ninterface ISkinnyIMTReadableEvent is IERC165 {\n /// @notice Tree `treeId`'s side nodes in the half-open range [firstIndex, endIndex).\n function getSkinnySideNodes(\n uint256 treeId,\n uint256 firstIndex,\n uint256 endIndex\n ) external view returns (uint256[] memory);\n\n /// @notice The current root of tree `treeId`.\n function getSkinnyRoot(uint256 treeId) external view returns (uint256);\n\n /// @notice The number of leaves in tree `treeId`.\n function getSkinnySize(uint256 treeId) external view returns (uint256);\n\n /// @notice The current depth of tree `treeId`.\n function getSkinnyDepth(uint256 treeId) external view returns (uint256);\n}\n"
219
+ },
220
+ "npm/@warptoad/skinny-imt.sol@0.0.11/interfaces/ISkinnyIMTReadableStorage.sol": {
221
+ "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.20;\n\nimport {ISkinnyIMTReadableEvent} from \"./ISkinnyIMTReadableEvent.sol\";\n\n/// @title ISkinnyIMTReadableStorage\ninterface ISkinnyIMTReadableStorage is ISkinnyIMTReadableEvent {\n /// @notice Tree `treeId`'s leaves in the half-open range [firstIndex, endIndex).\n function getSkinnyLeaves(\n uint256 treeId,\n uint256 firstIndex,\n uint256 endIndex\n ) external view returns (uint256[] memory);\n\n /// @notice Storage slot of tree `treeId`'s `leaves` array header, for clients reading the leaves\n /// straight out of storage rather than through an `eth_call`.\n function getSkinnyLeavesBaseSlot(uint256 treeId) external view returns (uint256);\n}\n"
222
+ },
223
+ "npm/@warptoad/skinny-imt.sol@0.0.11/InternalSkinnyIMTCore.sol": {
224
+ "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.4;\n\nimport {SNARK_SCALAR_FIELD} from \"./Constants.sol\";\n\n// TODO optimize duplicate inserts by adding hashed from 0 level nodes\nstruct SkinnyIMTData {\n // Tracks the current number of leaves in the tree.\n uint256 size;\n // Represents the current depth of the tree, which can increase as new leaves are inserted.\n uint256 depth;\n // A mapping from each level of the tree to the node value of the last even position at that level.\n // Used for efficient inserts, updates and root calculations.\n mapping(uint256 => uint256) sideNodes;\n //@TODO use since it can be retrieved extremely fast with debug_storageRangeAt\n //uint256[] public leaves;\n uint256 treeId;\n // caches the hash of a repeated value, so instead of doing hash(value,value)\n // you can lookup repeatedHashCache[value]\n mapping(uint256 => uint256) repeatedHashCache;\n}\n\nstruct MultiProof {\n uint256 treeDepth;\n uint256 edgeIndex;\n uint256[] leafIndexes;\n uint256[] proofSiblings;\n}\n\nerror WrongSiblingNodes();\nerror LeafDoesNotExist();\nerror WrongMultiProof();\nerror TreeEmpty();\n\n/// @title Skinny Incremental binary Merkle tree.\n/// @dev The SkinnyIMT is an optimized version of the BinaryIMT.\n/// This implementation eliminates the use of zeroes, and make the tree depth dynamic.\n/// When a node doesn't have the right child, instead of using a zero hash as in the BinaryIMT,\n/// the node's value becomes that of its left child. Furthermore, rather than utilizing a static tree depth,\n/// it is updated based on the number of leaves in the tree. This approach\n/// results in the calculation of significantly fewer hashes, making the tree more efficient.\nlibrary InternalSkinnyIMTCore {\n function _reset(SkinnyIMTData storage self) internal {\n self.size = 0;\n self.depth = 0;\n self.sideNodes[0] = 0; // so _root does not reference a invalid/stale root\n }\n\n /// @dev Inserts a new leaf into the incremental merkle tree.\n /// @notice Contracts using this function with snark based hash functions,\n // need to check that the leaf is within the snark scalar field.\n /// @param self: A storage reference to the 'SkinnyIMTData' struct.\n /// @param leaf: The value of the new leaf to be inserted into the tree.\n /// @return root, index\n function _insert(\n SkinnyIMTData storage self,\n uint256 leaf,\n function(uint256[2] memory) view returns (uint256) hasher\n ) internal returns (uint256, uint256) {\n // if (_isInitialized(self) == false) {\n // revert NotInitialized();\n // }\n uint256 index = self.size;\n\n // Cache tree depth to optimize gas\n uint256 treeDepth = self.depth;\n\n // A new insertion can increase a tree's depth by at most 1,\n // and only if the number of leaves supported by the current\n // depth is less than the number of leaves to be supported after insertion.\n if ((1 << treeDepth) < index + 1) {\n ++treeDepth;\n }\n\n self.depth = treeDepth;\n\n uint256 node = leaf;\n\n for (uint256 level = 0; level < treeDepth; ) {\n if ((index >> level) & 1 == 1) {\n // hash right\n node = hasher([self.sideNodes[level], node]);\n } else {\n // leave to dangle:\n // node is used in next iter, becomes it's own parent.\n if (((index + 1) >> level) & 1 == 1) {\n // only store it if the next insert actually needs it\n // that is when the next index is a right node at this level. That is when it reads from sideNodes\n // in the case above\n self.sideNodes[level] = node;\n }\n }\n\n unchecked {\n ++level;\n }\n }\n\n self.sideNodes[treeDepth] = node;\n // original did self.size = index++ above\n // since self.leaves[leaf] = index + 1. But that is no longer true\n self.size = index + 1;\n return (node, index);\n }\n\n /// @dev Per-level index/size trackers for `_insertMany`, bundled into one memory slot (one stack\n /// slot instead of four) so the function can also return the start/next indexes without blowing\n /// the 16-slot stack (no viaIR). Mutated in place as we climb: `currentLevel*` is the level being\n /// consumed, `nextLevel*` the level being built.\n struct InsertManyLevel {\n uint256 currentLevelStartIndex; // first index to change at the current level\n uint256 currentLevelSize; // number of nodes at the current level\n uint256 nextLevelStartIndex; // first index to change at the next level\n uint256 nextLevelSize; // number of nodes at the next level\n }\n\n /// @dev Inserts many leaves into the incremental merkle tree.\n /// @notice Contracts using this function with snark based hash functions,\n // need to check that the leafs are within the snark scalar field.\n /// @param self: A storage reference to the 'SkinnyIMTData' struct.\n /// @param leaves: The values of the new leaves to be inserted into the tree.\n /// @return root after the leaves have been inserted.\n /// @return startIndex index of the first appended leaf (inclusive).\n /// @return nextIndex index one past the last appended leaf (exclusive), matching\n /// `_insertManyRepeated` and the Event layer.\n function _insertMany(\n SkinnyIMTData storage self,\n uint256[] calldata leaves,\n function(uint256[2] memory) view returns (uint256) hasher\n ) internal returns (uint256, uint256, uint256) {\n // cache treeSize\n uint256 startIndex = self.size;\n\n // Array to save the nodes that will be used to create the next level of the tree.\n uint256[] memory currentLevelNewNodes;\n\n currentLevelNewNodes = leaves;\n\n // Cache tree depth to optimize gas\n uint256 treeDepth = self.depth;\n\n // Calculate the depth of the tree after adding the new values.\n // Unlike the 'insert' function, we need a while here as\n // N insertions can increase the tree's depth more than once.\n while ((1 << treeDepth) < startIndex + leaves.length) {\n ++treeDepth;\n }\n self.depth = treeDepth;\n\n // The four per-level trackers, packed into one memory slot (see InsertManyLevel) so the\n // frame has room for the two extra return values under the 16-slot stack limit (no viaIR).\n // currentLevel* describe the leaves just appended; nextLevel* is the level being built.\n InsertManyLevel memory lvl = InsertManyLevel({\n currentLevelStartIndex: startIndex, // first index to change in every level\n currentLevelSize: startIndex + leaves.length, // size of the level used to build the next\n nextLevelStartIndex: startIndex >> 1, // currentLevelStartIndex / 2\n nextLevelSize: ((startIndex + leaves.length - 1) >> 1) + 1 // ceil(currentLevelSize / 2)\n });\n\n for (uint256 level = 0; level < treeDepth; ) {\n // The number of nodes for the new level that will be created,\n // only the new values, not the entire level.\n // uint256 numberOfNewNodes = lvl.nextLevelSize - lvl.nextLevelStartIndex;\n uint256[] memory nextLevelNewNodes = new uint256[](lvl.nextLevelSize - lvl.nextLevelStartIndex);\n for (uint256 i = 0; i < lvl.nextLevelSize - lvl.nextLevelStartIndex; ) {\n // packing left and right node in one array saves on the stack size\n uint256[2] memory hasherInput;\n\n // Assign the left node using the saved path or the position in the array.\n if (((i + lvl.nextLevelStartIndex) << 1) < lvl.currentLevelStartIndex) {\n hasherInput[0] = self.sideNodes[level];\n } else {\n hasherInput[0] = currentLevelNewNodes[\n ((i + lvl.nextLevelStartIndex) << 1) - lvl.currentLevelStartIndex\n ];\n }\n\n // Existence of a right child by checking index\n // zero is a valid leaf now, so `rightChild == 0` can't be used as a proxy.\n // If a right child exists: assign it and hash(left, right). Otherwise: parent = left.\n if (((i + lvl.nextLevelStartIndex) << 1) + 1 < lvl.currentLevelSize) {\n hasherInput[1] = currentLevelNewNodes[\n ((i + lvl.nextLevelStartIndex) << 1) + 1 - lvl.currentLevelStartIndex\n ];\n // store as parent node for next round\n nextLevelNewNodes[i] = hasher(hasherInput);\n } else {\n // leave to dangle:\n // node is used in next iter, becomes it's own parent.\n // Stored in nextLevelNewNodes, for when it will have an right sibling eventually\n // store as parent node for next round\n nextLevelNewNodes[i] = hasherInput[0];\n }\n\n unchecked {\n ++i;\n }\n }\n\n // Update the `sideNodes` variable.\n // sideNodes are always at the edge of the tree, and are always the leftChild\n //\n // If `lvl.currentLevelSize` is odd, the saved value will be the last value of the array\n // if it is even and there are more than 1 element in `currentLevelNewNodes`, the saved value\n // will be the value before the last one.\n // If it is even and there is only one element, there is no need to save anything because\n // the correct value for this level was already saved before.\n // Only refresh the sideNode at levels live for the new tree (set bits of the\n // new leaf count). At the other levels the next insert overwrites the slot\n // before reading it, so the store would be dead. (Computed inline rather than\n // cached in a local — the surrounding function is at the 16-slot stack limit.)\n if (((startIndex + leaves.length) >> level) & 1 == 1) {\n if (lvl.currentLevelSize & 1 == 1) {\n // lvl.currentLevelSize % 2 == 1, is odd\n // lvl.currentLevelSize = treeSize + leaves.length\n // lvl.currentLevelSize = (lvl.currentLevelSize - 1) / 2 + 1\n self.sideNodes[level] = currentLevelNewNodes[currentLevelNewNodes.length - 1];\n } else if (currentLevelNewNodes.length > 1) {\n self.sideNodes[level] = currentLevelNewNodes[currentLevelNewNodes.length - 2];\n }\n }\n\n lvl.currentLevelStartIndex = lvl.nextLevelStartIndex;\n\n // Calculate the next level startIndex value.\n // It is the position of the parent node which is pos/2.\n lvl.nextLevelStartIndex >>= 1;\n\n // Update the next array that will be used to calculate the next level.\n currentLevelNewNodes = nextLevelNewNodes;\n\n lvl.currentLevelSize = lvl.nextLevelSize;\n\n // Calculate the size of the next level.\n // The size of the next level is (lvl.currentLevelSize - 1) / 2 + 1.\n lvl.nextLevelSize = ((lvl.nextLevelSize - 1) >> 1) + 1;\n\n unchecked {\n ++level;\n }\n }\n\n // Update tree size\n self.size = startIndex + leaves.length;\n\n self.sideNodes[treeDepth] = currentLevelNewNodes[0];\n\n return (currentLevelNewNodes[0], startIndex, startIndex + leaves.length);\n }\n\n /// @dev Returns `hasher(currentNode, currentNode)`, reading the cache when\n /// warm and computing+storing on a miss. Generic memoizer for `f(x) = H(x, x)`:\n /// any chain that reaches `currentNode` at any level for any starting value\n /// shares the same entry. Factored out of the main loop to keep the\n /// per-iteration stack under Solidity's 16-slot limit.\n /// @param self: A storage reference to the 'SkinnyIMTData' struct.\n /// @param value: The value to hash with itself.\n /// @return `hasher(currentNode, currentNode)`.\n function _hashWithCache(\n SkinnyIMTData storage self,\n uint256 value,\n function(uint256[2] memory) view returns (uint256) hasher\n ) private returns (uint256) {\n uint256 cached = self.repeatedHashCache[value];\n if (cached != 0) {\n return cached;\n }\n uint256 hash = hasher([value, value]);\n self.repeatedHashCache[value] = hash;\n return hash;\n }\n\n /// @dev Appends `amount` leaves all equal to `value` into the tree.\n /// @notice Worst case costs 3*newDepth hashes regardless of `amount`.\n /// Best case cost 1*newDepth\n ///\n /// Only hashes 3 paths:\n /// repeatedCenterNode: in the center of the insert,\n /// these only contain nodes of \"a balanced tree with only the same value repeating\".\n /// ex: H(0,0), H(H(0,0),H(0,0)), etc\n /// Majority of the hashes the same as a repeatedCenterNode at every level.\n /// Re-using those hashes instead of re-hashing is the core of the optimization here\n /// lefBoundaryNodes: at the left of the insert who mix with the existing tree.\n /// rightEdgeNodes: at the right of the insert and tree, tracks potential dangling nodes to to root\n /// Eventually meets lefBoundaryNodes and creates the root.\n ///\n /// both lefBoundaryNodes and rightEdgeNodes use repeatedCenterNode to attach to the rest of the inserted sub tree.\n /// Best case cost is O(1*newDepth) because both lefBoundaryNodes and rightEdgeNodes,\n /// will use nodes from repeatedCenterNode when ever they can.\n /// And when a insert results in an balanced tree and previous tree is empty, that is alway the case.\n /// So it become O(1*newTreeDepth)\n /// @param self: A storage reference to the 'SkinnyIMTData' struct.\n /// @param value: The leaf value to insert `amount` copies of.\n /// @param amount: The number of leaves to append.\n /// @return root after the leaves have been appended.\n /// @return startIndex index of the first appended leaf (inclusive).\n /// @return nextIndex The next index of the insert *after* this call.\n /// Note: nextIndex is frequently used to derive the edgeIndex by doing `nextIndex-1`.\n /// This to save space on the stack\n function _insertManyRepeated(\n SkinnyIMTData storage self,\n uint256 value,\n uint256 amount,\n function(uint256[2] memory) view returns (uint256) hasher\n ) internal returns (uint256 root, uint256 startIndex, uint256 nextIndex) {\n uint256 newTreeDepth = self.depth;\n startIndex = self.size;\n {\n // NOTE: named returns are avoided in this package (to prevent initialization footguns)\n // but here it had to be used because the tight stack limit\n\n nextIndex = startIndex + amount;\n while (1 << newTreeDepth < nextIndex) {\n unchecked {\n ++newTreeDepth;\n }\n }\n\n if (amount == 0) {\n // nothing appended: the exclusive end is startIndex itself\n return (_root(self), startIndex, startIndex);\n }\n if (amount == 1) {\n (root, ) = _insert(self, value, hasher);\n return (root, startIndex, nextIndex);\n }\n\n self.depth = newTreeDepth;\n self.size = nextIndex;\n }\n\n // Nodes at the edges of the insert, and the center where the node only contains zeros:\n // lefBoundaryNode = The node at the boundary between the insert and existing tree.\n // rightEdgeNode = The node that is at the very edge of the tree.\n // repeatedCenterNode = The node that all sit in the center of the insert and\n // only contain repeated values and is always balanced. Always cache-able\n uint256 leftBoundaryNode = value;\n uint256 rightEdgeNode = value;\n uint256 repeatedCenterNode = value;\n\n // loops only once over the newTreeDepth\n // does at most 3 hashes,\n // 2 hashes for the left and right side of the inserted values (lefEdgeNode, rightEdgeNode)\n // 1 hash / cache lookup for the node that only contains zeros (repeatedCenterNode)\n for (uint256 level = 0; level < newTreeDepth; ) {\n // ------------assign sideNode --------------\n uint256 oldSideNode = self.sideNodes[level];\n uint256 newSideNode;\n {\n // calculate the current index of the most left and right node of the insert\n // by doing: index >> level (same as: index / 2^level). (nextIndex - 1) is the\n // inclusive last leaf index; see the return docs on why we keep only nextIndex.\n uint256 rightEdgePosition = (nextIndex - 1) >> level;\n uint256 leftBoundaryPosition = startIndex >> level;\n\n // determine where the sideNode is at. Left,right, (somewhere) center of the inserted nodes or unchanged\n // sideNode == rightEdgeNodeSibling (left sibling of rightEdge), unless dangles or if root\n if (rightEdgePosition & 1 == 0) {\n // here rightEdgeNode is at an uneven index, because it is at the very edge of the entire tree,\n // it will have no sibling :(, it will \"dangle\" and thus will be the newSideNode\n newSideNode = rightEdgeNode;\n\n // these cases when rightEdgeNode does have a sibling :D\n // now we just detect who is that sibling. leftBoundary, repeatedCenter or oldSideNode?\n } else if (leftBoundaryPosition < (rightEdgePosition - 1)) {\n // rightEdgeNode has a sibling :D\n // But that sibling is not leftBoundaryPosition yet, since the position of\n // the sibling of rightEdgeNode (rightEdgePosition - 1) is higher then leftBoundaryPosition\n // There for we need a sibling between the old tree and the very right edge,\n // we need repeatedCenterNode!\n newSideNode = repeatedCenterNode;\n } else if (leftBoundaryPosition == (rightEdgePosition - 1)) {\n // Now rightEdgeNode's sibling positions is *exactly* leftBoundaryPosition\n // it's sibling is leftBoundaryNode!\n newSideNode = leftBoundaryNode;\n } else {\n // now leftBoundaryPosition is the same as rightEdgePosition\n // we know this because leftBoundaryPosition < rightEdgeSiblingPosition (else if #1)\n // and leftBoundaryPosition != rightEdgeSiblingPosition (else if #2)\n // and because node position only converge when moving up a tree, but never cross,\n // we can now say leftBoundaryNode is at the same position as rightEdgeNode\n // because leftBoundaryNode and rightEdgeNode are the same, they form a subTreeRoot that contains\n // all values we are inserting (sometimes some values of existing tree).\n // Now we need to just \"attach\" this root with our inserts to the existing tree\n // simply by constantly hashing in the oldSideNode of that level.\n newSideNode = oldSideNode;\n }\n }\n\n // `newSideNode != oldSideNode`: skip obviously redundant writes\n // `(nextIndex >> level) & 1 == 1`: check if the next insert (after this function is done)\n // who needs a right sibling, but will not have that yet while inserting (after this function is done)\n // so it has no right sibling, and instead takes a sideNode as it's *left* sibling to attach to the tree.\n // only in that specific case is a sideNode read, so only then we write to it.\n // @TODO put this explanation else where and refer to it any time `(nextIndex >> level) & 1 == 1` happens.\n if (newSideNode != oldSideNode && (nextIndex >> level) & 1 == 1) {\n self.sideNodes[level] = newSideNode;\n }\n\n //-------- hashing -----------------\n {\n // ---- repeatedCenterNode---\n // newRepeatedCenterNode use a cache to look hashes from a \"balanced tree with only repeated values\"\n uint256 newRepeatedCenterNode = _hashWithCache(self, repeatedCenterNode, hasher);\n\n // ----leftBoundaryNode---\n // calculate index of the left boundary node at this level and check if it's odd or even, left or right\n // oldSize / (2**level) % 2\n {\n // redoing calculation here because of stack limits\n // uint256 leftBoundaryPosition = startIndex >> level; over stack limit again :/\n uint256 nextRightEdgePosition = (nextIndex - 1) >> (level + 1);\n uint256 nextLeftEdgePosition = startIndex >> (level + 1);\n\n // we can skip leftBoundaryNode if the next iter rightEdgeNode is at the same position\n // at that point leftBoundaryNode does the same as rightEdgeNode,\n // so no need to do things twice\n if (nextLeftEdgePosition != nextRightEdgePosition) {\n // if leftBoundaryPosition is right\n if ((startIndex >> level) & 1 == 1) {\n // if right use oldSideNode, since that is where these added nodes \"attach\" to the\n // existing tree\n if (leftBoundaryNode == repeatedCenterNode && oldSideNode == repeatedCenterNode) {\n // no need to hash, already done by newRepeatedCenterNode!\n // oldSideNode was just a N-hashed repeated value\n leftBoundaryNode = newRepeatedCenterNode;\n } else {\n // existing tree had something else, no luck!\n leftBoundaryNode = hasher([oldSideNode, leftBoundaryNode]);\n }\n } else {\n // if left, use the repeatedCenterNode,\n // (could be one if but requires another var on the stack)\n if (leftBoundaryNode == repeatedCenterNode) {\n // no need to hash, already done by newRepeatedCenterNode!\n leftBoundaryNode = newRepeatedCenterNode;\n } else {\n // our boundary node picked up an existing value from the existing tree\n // that is not our value we are repeatedly inserting. No luck :(\n leftBoundaryNode = hasher([leftBoundaryNode, repeatedCenterNode]);\n }\n }\n }\n }\n\n // ---- rightEdgeNode ---\n // calculate index of the newSide node at this level and check if it's odd or even\n // rightEdgePosition =((nextIndex - 1) >> level)\n if (((nextIndex - 1) >> level) & 1 == 1) {\n // if odd rightEdgeNode has a sibling so we hash it right\n if (newSideNode == rightEdgeNode) {\n // we are doing hasher([rightEdgeNode, rightEdgeNode])\n if (repeatedCenterNode == rightEdgeNode) {\n // it's just a center node\n rightEdgeNode = newRepeatedCenterNode;\n } else {\n // we might be doing hasher([rightEdgeNode, rightEdgeNode])\n // as a coincidence. Or we did do a \"balanced tree with only repeated values\" hash\n // check the cache\n uint256 cached = self.repeatedHashCache[rightEdgeNode];\n if (cached != 0) {\n rightEdgeNode = cached; // free hash\n } else {\n // not storing this because it might have been a coincidence\n rightEdgeNode = hasher([rightEdgeNode, rightEdgeNode]);\n }\n }\n } else {\n rightEdgeNode = hasher([newSideNode, rightEdgeNode]);\n }\n }\n // we don't do the left case since we need to leave rightEdgeNode to dangle\n\n // repeatedCenterNode updates for the next iter\n repeatedCenterNode = newRepeatedCenterNode;\n }\n\n // Advance level first so it doubles as `nextLevel` for the cache lift.\n unchecked {\n ++level;\n }\n }\n\n // finally store the root!\n root = rightEdgeNode;\n self.sideNodes[newTreeDepth] = root;\n return (root, startIndex, nextIndex);\n }\n\n /// @dev Warms the `(value, level)` cache for levels 1..`upToLevel` so that\n /// subsequent `_insertManyRepeated(value, ...)` calls hit the cache instead of\n /// re-hashing. Idempotent: levels already cached are not rewritten.\n /// @notice Useful when you know in advance the maximum depth a tree will reach\n /// for a particular `value` (e.g. zero) — pay the SSTOREs once, then every\n /// subsequent bulk-insert of that value reads cheaply from storage.\n /// @notice Reverts if the tree has not been initialized.\n /// @param self: A storage reference to the 'SkinnyIMTData' struct.\n /// @param value: The leaf value whose repeated-subtree chain to precompute.\n /// @param upToLevel: The highest level (inclusive) to populate the cache for.\n function _precomputeRepeatedCache(\n SkinnyIMTData storage self,\n uint256 value,\n uint256 upToLevel,\n function(uint256[2] memory) view returns (uint256) hasher\n ) internal {\n if (upToLevel == 0) {\n return;\n }\n\n // subtreeRoot tracks the repeated-subtree root at the current level as we\n // climb. Start at level 0 = value. Each iteration looks up (or fills)\n // hasher(subtreeRoot, subtreeRoot) and advances one level.\n uint256 subtreeRoot = value;\n for (uint256 level = 1; level <= upToLevel; ) {\n subtreeRoot = _hashWithCache(self, subtreeRoot, hasher);\n unchecked {\n ++level;\n }\n }\n }\n\n /// @dev Updates the value of an existing leaf and recalculates hashes\n /// to maintain tree integrity.\n /// @param self: A storage reference to the 'SkinnyIMTData' struct.\n /// @param oldLeaf: The value of the leaf that is to be updated.\n /// @param newLeaf: The new value that will replace the oldLeaf in the tree.\n /// @param leafIndex: The index of the leaf to be updated.\n /// @param proofSiblings: An array of sibling nodes that are necessary to recalculate the path to the root.\n /// @return The new hash of the updated node after the leaf has been updated.\n /// @notice Requires collision-resistant hashing: `if (self.sideNodes[level] == oldRoot)` identifies\n /// which sideNode to refresh by hash equality,\n /// so a collision between two distinct subtree roots would corrupt tree state silently.\n /// @notice Contracts using this function with snark based hash functions,\n /// need to check that the old and newLeaf and proofSiblings are within the snark scalar field.\n function _update(\n SkinnyIMTData storage self,\n uint256 oldLeaf,\n uint256 newLeaf,\n uint256 leafIndex,\n uint256[] calldata proofSiblings,\n function(uint256[2] memory) view returns (uint256) hasher\n ) internal returns (uint256) {\n // Cache tree depth to optimize gas\n uint256 treeDepth = self.depth;\n if (proofSiblings.length > treeDepth) {\n revert WrongSiblingNodes();\n }\n\n // 2 vars to store intermediate hashes, to hash up to oldRoot and newRoot\n uint256 newNode = newLeaf;\n uint256 oldNode = oldLeaf;\n\n // index of the very last leaf in the tree\n // tracking this index up the tree, follows the indexes of the nodes in self.sidNodes\n uint256 treeSize = self.size;\n uint256 edgeIndex = treeSize - 1;\n\n // because leanIMT is not balanced proofSiblings.length can be smaller then tree depth\n // we cant just use level so we separately track those 2\n uint256 siblingIndex = 0;\n\n // verify merkle proof of oldLeaf from proofSiblings\n // and at the same time calculate the newRoot\n\n // note: this is basically just _proofToRoot twice on old and new leaf, then assert root from oldLeaf is\n // the current root. Difference is that self.sideNodes[level] = newNode gets assigned when newNode is an\n // edge node. Thats when newNode is left.\n for (uint256 level = 0; level < treeDepth; ) {\n // leafIndex is odd / is right\n if ((leafIndex >> level) & 1 == 1) {\n // no newNode to store in sideNodes to store here, the next insert does not need it if it already\n // has a sibling\n newNode = hasher([proofSiblings[siblingIndex], newNode]);\n oldNode = hasher([proofSiblings[siblingIndex], oldNode]);\n\n unchecked {\n ++siblingIndex;\n }\n } else {\n if (leafIndex >> level != edgeIndex >> level) {\n // does the index of newNode at the current level,\n // share a parent with the lastIndex at the current level?\n // So newNode/lastIndex current index == index >> level, then add +1 to level to get the parent\n\n // @notice used to be simple self.sideNodes[level] == oldNode equality check in leanIMT,\n // but duplicate values occurring break this assumption\n //\n // The geometry test (shares a parent with the last leaf) says this node IS the one\n // stored in sideNodes[level]. The extra `(treeSize >> level) & 1 == 1` is a liveness\n // filter: the slot is only read again if the next appended leaf lands as a right child\n // at this level (a set bit of the leaf count). Otherwise the next insert overwrites the\n // slot before reading, so refreshing it here would be a dead write.\n if ((treeSize >> level) & 1 == 1 && leafIndex >> (level + 1) == edgeIndex >> (level + 1)) {\n // because the leanIMT structure creates a unbalanced tree which hoist internal nodes or leafs\n // up if the size is not even after a insert.\n // the sideNodes being stored is not always at edgeIndex. At size 5 for example. Index 4 needs\n // the grand parent of 0,1,2,3. And 4 is hoisted up to that level and hashed with\n // that grand parent. Which is hash(grandParent, index_4).\n // This only happens if the next node above is a edgeNode. That's why we check:\n // leafIndex >> (level + 1) == edgeIndex >> (level + 1)\n // But that stores every node that happens to have a left sibling that is an edge node.\n // But we don't need all of those, because the next insert only needs siblings that are left\n // to the insert. So we do\n // (treeSize >> level) & 1 == 1\n // treeSize == nextInsertIndex. And we check if the next insert of the index lays to the left\n // thus needs to do hash(sidNodes,insertedNode). Which is the only case we actually need to\n // have this side node\n self.sideNodes[level] = newNode;\n }\n\n newNode = hasher([newNode, proofSiblings[siblingIndex]]);\n oldNode = hasher([oldNode, proofSiblings[siblingIndex]]);\n\n unchecked {\n ++siblingIndex;\n }\n } else if ((treeSize >> level) & 1 == 1) {\n // cary up this side node, it dangles (same liveness filter as above)\n self.sideNodes[level] = newNode;\n }\n // others that aren't leafs get carried up without adding to sideNodes\n }\n\n unchecked {\n ++level;\n }\n }\n\n if (oldNode != _root(self)) {\n revert WrongSiblingNodes();\n }\n\n self.sideNodes[treeDepth] = newNode;\n\n return newNode;\n }\n\n /// @dev Hashes merkle proof and returns the root the leaf belongs to\n /// @param leafIndex: The leaf to proof inclusion of\n /// @param leafIndex: The index of the leaf within the tree.\n /// @param proofSiblings: The sibling nodes along the path from the leaf to the root.\n /// @return The root obtained from hashing the leaf with the provided siblings.\n /// @notice Contracts using this function with snark based hash functions,\n /// need to check that the leaf and proofSiblings are within the snark scalar field.\n function _proofToRoot(\n uint256 treeDepth,\n uint256 treeSize,\n uint256 leaf,\n uint256 leafIndex,\n uint256[] calldata proofSiblings,\n function(uint256[2] memory) view returns (uint256) hasher\n ) internal view returns (uint256) {\n if (treeSize == 0) {\n revert TreeEmpty();\n }\n\n // index of the very last leaf in the tree\n // tracking this index up the tree, follows the indexes of the nodes in self.sidNodes\n uint256 edgeIndex = treeSize - 1;\n\n // because leanIMT is not balanced proofSiblings.length can be smaller then tree depth\n // we cant just use level so we separately track those 2\n uint256 siblingIndex = 0;\n\n uint256 node = leaf;\n for (uint256 level = 0; level < treeDepth; ) {\n if ((leafIndex >> level) & 1 == 1) {\n node = hasher([proofSiblings[siblingIndex], node]);\n\n unchecked {\n ++siblingIndex;\n }\n } else {\n // make sure node index is not at the edge @TODO explain\n if (leafIndex >> level != edgeIndex >> level) {\n node = hasher([node, proofSiblings[siblingIndex]]);\n\n unchecked {\n ++siblingIndex;\n }\n }\n }\n\n unchecked {\n ++level;\n }\n }\n return node;\n }\n\n struct MultiProofLevel {\n // One level's known nodes and their positions. The fold rewrites parents in place into\n // the low end of these same arrays: the write cursor (nextNodesFreeSlot) never runs ahead\n // of the read index, and the only forward read (the i+1 sibling) is always still unwritten,\n // so a single buffer aliases safely. `currentNodesFreeSlot` bounds the live prefix.\n uint256[] nodes;\n uint256[] positions;\n }\n\n struct MultiProofArrLevelPositions {\n uint256 currentNodesFreeSlot;\n uint256 nextNodesFreeSlot;\n uint256 proofSiblingsReadPos;\n uint256 edgePos;\n uint256 level;\n uint256 newSideNode;\n bool isNewSideNode;\n }\n\n /// @dev Folds one tree level: reads the known nodes in `nodes` (positions in `positions`)\n /// and rewrites their parents into the low end of those same arrays in place,\n /// pulling a sibling from `proof.proofSiblings` only where one isn't already known.\n /// A rightmost node with no sibling (position == edgePos) is carried up unchanged — this\n /// is where dangling (a leaf or an internal node with no right neighbor) is resolved,\n /// entirely from the tree's `edgeIndex`, not from any caller-supplied schedule.\n function _hashMultiProofLevel(\n MultiProof memory proof,\n MultiProofLevel memory lvl,\n MultiProofArrLevelPositions memory lvlPos,\n function(uint256[2] memory) view returns (uint256) hasher\n ) private view returns (MultiProofLevel memory, MultiProofArrLevelPositions memory) {\n // The sideNode at this level is, by definition, the node at position (treeSize >> level) - 1,\n // and it only exists (is read by a future insert) when this level is live: (treeSize >> level) & 1 == 1.\n // That position is always even (a left / left-frontier node), so the main loop below always visits it\n // (only odd siblings are skipped via `continue`). When not live, use a sentinel that no position matches.\n // If that exact node is among the ones we recompute, we hand its new value back so the caller can store\n // it into self.sideNodes[level]. This uniformly covers the \"shares a parent with the edge\" case and the\n // dangling-edge case, and stores the node AT this level (never its parent).\n uint256 treeSize = proof.edgeIndex + 1;\n uint256 frontierPos = ((treeSize >> lvlPos.level) & 1 == 1)\n ? (treeSize >> lvlPos.level) - 1\n : type(uint256).max;\n\n lvlPos.isNewSideNode = false;\n for (uint256 i = 0; i < lvlPos.currentNodesFreeSlot; i++) {\n if (lvl.positions[i] == frontierPos) {\n lvlPos.newSideNode = lvl.nodes[i];\n lvlPos.isNewSideNode = true;\n }\n\n // hash left or right\n if (lvl.positions[i] & 1 == 1) {\n // A right-position node whose sibling is also known is consumed at that sibling\n // (the even node below, which skips forward past this one), so reaching here means\n // the left sibling isn't in currentNodes and must come from the proof.\n lvl.nodes[lvlPos.nextNodesFreeSlot] = hasher(\n [proof.proofSiblings[lvlPos.proofSiblingsReadPos], lvl.nodes[i]]\n );\n lvl.positions[lvlPos.nextNodesFreeSlot] = lvl.positions[i] >> 1;\n\n unchecked {\n ++lvlPos.nextNodesFreeSlot;\n ++lvlPos.proofSiblingsReadPos;\n }\n } else {\n // make sure node index is not at the edge because edges should be carried up a level\n // TODO these variable names are so long the auto format makes the code unreadable\n if (lvl.positions[i] != lvlPos.edgePos) {\n if ((i + 1) < lvlPos.currentNodesFreeSlot && (lvl.positions[i + 1] == (lvl.positions[i] + 1))) {\n // the right sibling is the next node in currentNodes, so hash the pair\n // here and skip it (avoids reading a left neighbor on the next iteration)\n lvl.nodes[lvlPos.nextNodesFreeSlot] = hasher([lvl.nodes[i], lvl.nodes[i + 1]]);\n lvl.positions[lvlPos.nextNodesFreeSlot] = lvl.positions[i] >> 1;\n // up counter to skip next node since we already hashed it.\n unchecked {\n ++i;\n }\n } else {\n lvl.nodes[lvlPos.nextNodesFreeSlot] = hasher(\n [lvl.nodes[i], proof.proofSiblings[lvlPos.proofSiblingsReadPos]]\n );\n lvl.positions[lvlPos.nextNodesFreeSlot] = lvl.positions[i] >> 1;\n\n unchecked {\n ++lvlPos.proofSiblingsReadPos;\n }\n }\n } else {\n lvl.nodes[lvlPos.nextNodesFreeSlot] = lvl.nodes[i];\n lvl.positions[lvlPos.nextNodesFreeSlot] = lvl.positions[i] >> 1;\n }\n ++lvlPos.nextNodesFreeSlot;\n }\n }\n\n // per level updates\n lvlPos.edgePos >>= 1;\n\n // parents were written in place into the low slots; that prefix is the next level.\n lvlPos.currentNodesFreeSlot = lvlPos.nextNodesFreeSlot;\n lvlPos.nextNodesFreeSlot = 0;\n return (lvl, lvlPos);\n }\n\n // would save 2 array in memory, more importantly stack pressure\n function _proofManyToRoot(\n uint256[] calldata leaves,\n MultiProof memory proof,\n function(uint256[2] memory) view returns (uint256) hasher\n ) internal view returns (uint256) {\n uint256 leafCount = leaves.length;\n if (leafCount == 0 || leafCount != proof.leafIndexes.length) {\n revert WrongMultiProof();\n }\n\n MultiProofLevel memory lvl = MultiProofLevel(new uint256[](leafCount), new uint256[](leafCount));\n\n MultiProofArrLevelPositions memory lvlPos = MultiProofArrLevelPositions(0, 0, 0, proof.edgeIndex, 0, 0, false);\n\n // Seed every proven leaf at level 0, at its real index. Each leaf is then hashed up\n // from the bottom, so an internal-node value or a wrong index simply produces a\n // non-matching root — nothing can enter above level 0 un-hashed. Dangling is resolved\n // while climbing (the edge-carry in _hashMultiProofLevel), derived from `edgeIndex`.\n for (uint256 i = 0; i < leafCount; i++) {\n lvl.nodes[i] = leaves[i];\n lvl.positions[i] = proof.leafIndexes[i];\n }\n lvlPos.currentNodesFreeSlot = leafCount;\n\n for (uint256 level = 0; level < proof.treeDepth; ) {\n lvlPos.level = level;\n (lvl, lvlPos) = _hashMultiProofLevel(proof, lvl, lvlPos, hasher);\n\n unchecked {\n ++level;\n }\n }\n\n // all proof siblings need to be read and validated.\n // Very strict but now this function verifies leaves + indexes + proof siblings\n if (lvlPos.proofSiblingsReadPos != proof.proofSiblings.length) {\n revert WrongMultiProof();\n }\n return lvl.nodes[0];\n }\n\n // would save 2 array in memory, more importantly stack pressure\n function _updateMany(\n SkinnyIMTData storage self,\n uint256[] calldata oldLeaves,\n uint256[] calldata newLeaves,\n MultiProof memory proof,\n function(uint256[2] memory) view returns (uint256) hasher\n ) internal returns (uint256) {\n uint256 leafCount = oldLeaves.length;\n if (leafCount == 0 || leafCount != proof.leafIndexes.length || leafCount != newLeaves.length) {\n revert WrongMultiProof();\n }\n\n MultiProofLevel memory oldLvl = MultiProofLevel(new uint256[](leafCount), new uint256[](leafCount));\n\n MultiProofLevel memory newLvl = MultiProofLevel(new uint256[](leafCount), new uint256[](leafCount));\n MultiProofArrLevelPositions memory newLvlPos = MultiProofArrLevelPositions(\n 0,\n 0,\n 0,\n proof.edgeIndex,\n 0,\n 0,\n false\n );\n\n MultiProofArrLevelPositions memory oldLvlPos = MultiProofArrLevelPositions(\n 0,\n 0,\n 0,\n proof.edgeIndex,\n 0,\n 0,\n false\n );\n\n // Seed every proven leaf at level 0, at its real index. Each leaf is then hashed up\n // from the bottom, so an internal-node value or a wrong index simply produces a\n // non-matching root — nothing can enter above level 0 un-hashed. Dangling is resolved\n // while climbing (the edge-carry in _hashMultiProofLevel), derived from `edgeIndex`.\n for (uint256 i = 0; i < leafCount; i++) {\n oldLvl.nodes[i] = oldLeaves[i];\n newLvl.nodes[i] = newLeaves[i];\n oldLvl.positions[i] = proof.leafIndexes[i];\n newLvl.positions[i] = proof.leafIndexes[i];\n }\n oldLvlPos.currentNodesFreeSlot = leafCount;\n newLvlPos.currentNodesFreeSlot = leafCount;\n\n for (uint256 level = 0; level < proof.treeDepth; ) {\n oldLvlPos.level = level;\n newLvlPos.level = level;\n (oldLvl, oldLvlPos) = _hashMultiProofLevel(proof, oldLvl, oldLvlPos, hasher);\n (newLvl, newLvlPos) = _hashMultiProofLevel(proof, newLvl, newLvlPos, hasher);\n\n if (newLvlPos.isNewSideNode) {\n self.sideNodes[level] = newLvlPos.newSideNode;\n }\n\n unchecked {\n ++level;\n }\n }\n // Verify the old leaves against the current root BEFORE overwriting anything: _root(self) still\n // reads the old top slot here. The loop above only refreshed intermediate sideNodes (levels\n // < treeDepth); the top root slot is written below, once the proof is known good.\n if (_root(self) != oldLvl.nodes[0]) {\n // TODO say wrong root instead? Also in _update?\n revert WrongMultiProof();\n }\n\n // all proof siblings need to be read and validated.\n // Very strict but now this function verifies leaves + indexes + proof siblings\n if (oldLvlPos.proofSiblingsReadPos != proof.proofSiblings.length) {\n revert WrongMultiProof();\n }\n\n // Store the new top root (mirrors _update's `self.sideNodes[treeDepth] = newNode`). An update\n // never changes depth, so proof.treeDepth == self.depth.\n uint256 newRoot = newLvl.nodes[0];\n self.sideNodes[proof.treeDepth] = newRoot;\n return newRoot;\n }\n\n /// @dev Retrieves the root of the tree from the 'sideNodes' mapping using the\n /// current tree depth.\n /// @param self: A storage reference to the 'SkinnyIMTData' struct.\n /// @return The root hash of the tree.\n function _root(SkinnyIMTData storage self) internal view returns (uint256) {\n return self.sideNodes[self.depth];\n }\n}\n\n// @notes contract size limit work around: use _hashMultiProofLevel for both proofManyToRoot as updateMany\n// same with plain update\n// _hashMultiProofLevel uses 2 arrays for tracking nodes. currentLevel and nextLevel. You can prob just do it in 1\n// same for insertMany probably, but that is vivians code so i would rather keep it as similar as possible\n// and ofc we can just split into multiple contracts that export these internal functions. example move verify functions\n// outside of SkinnyIMTPoseidon2WriteEvent\n\n// old unused code\n// this is not used because it only adds to contract size and gas of these functions.\n// it does read easier and more consistently with the other implementation\n//------------ update and proofToRoot written with hashLevel pattern like updateMany and proofManyToRoot -------------\n// /// @dev Updates the value of an existing leaf and recalculates hashes\n// /// to maintain tree integrity.\n// /// @param self: A storage reference to the 'SkinnyIMTData' struct.\n// /// @param oldLeaf: The value of the leaf that is to be updated.\n// /// @param newLeaf: The new value that will replace the oldLeaf in the tree.\n// /// @param leafIndex: The index of the leaf to be updated.\n// /// @param proofSiblings: An array of sibling nodes that are necessary to recalculate the path to the root.\n// /// @return The new hash of the updated node after the leaf has been updated.\n// /// @notice Requires collision-resistant hashing: `if (self.sideNodes[level] == oldRoot)` identifies\n// /// which sideNode to refresh by hash equality,\n// /// so a collision between two distinct subtree roots would corrupt tree state silently.\n// /// @notice Contracts using this function with snark based hash functions,\n// /// need to check that the old and newLeaf and proofSiblings are within the snark scalar field.\n// function _update(\n// SkinnyIMTData storage self,\n// uint256 oldLeaf,\n// uint256 newLeaf,\n// uint256 leafIndex,\n// uint256[] calldata proofSiblings,\n// function(uint256[2] memory) view returns (uint256) hasher\n// ) internal returns (uint256) {\n// if (_isInitialized(self) == false) {\n// revert NotInitialized();\n// }\n// // Cache tree depth to optimize gas\n// uint256 treeDepth = self.depth;\n// if (proofSiblings.length > treeDepth) {\n// revert WrongSiblingNodes();\n// }\n\n// uint256 treeSize = self.size;\n\n// // 2 vars to store intermediate hashes, to hash up to oldRoot and newRoot\n// uint256 newNode = newLeaf;\n// uint256 oldNode = oldLeaf;\n\n// ProofLevelPositions memory oldLevelPos = ProofLevelPositions(\n// leafIndex, // nodeIndex\n// treeSize - 1, // edgeIndex\n// treeSize, // nextInsertIndex\n// 0, // proofSiblingReadIndex\n// 0, // newSideNode\n// false // isNewSideNode\n// );\n// ProofLevelPositions memory newLevelPos = ProofLevelPositions(\n// leafIndex, // nodeIndex\n// treeSize - 1, // edgeIndex\n// treeSize, // nextInsertIndex\n// 0, // proofSiblingReadIndex\n// 0, // newSideNode\n// false // isNewSideNode\n// );\n// for (uint256 level = 0; level < treeDepth; ) {\n// // oldNode is just inclusion proof, so trackSideNodes=false, and we will use the same positions for newNode\n// // so trackPositions=false\n// (oldNode, oldLevelPos) = _hashProofLevel(oldNode, oldLevelPos, proofSiblings, hasher);\n// (newNode, newLevelPos) = _hashProofLevel(newNode, newLevelPos, proofSiblings, hasher);\n// if (newLevelPos.isNewSideNode) {\n// self.sideNodes[level] = newLevelPos.newSideNode;\n// }\n// unchecked {\n// ++level;\n// }\n// }\n\n// if (oldNode != _root(self)) {\n// revert WrongSiblingNodes();\n// }\n\n// self.sideNodes[treeDepth] = newNode;\n\n// return newNode;\n// }\n\n// struct ProofLevelPositions {\n// uint256 nodeIndex;\n// uint256 edgeIndex;\n// uint256 nextInsertIndex;\n// uint256 siblingIndex;\n// uint256 newSideNode;\n// bool isNewSideNode;\n// }\n\n// function _hashProofLevel(\n// uint256 node,\n// ProofLevelPositions memory lvlPos,\n// uint256[] calldata proofSiblings,\n// function(uint256[2] memory) view returns (uint256) hasher\n// ) internal view returns (uint256, ProofLevelPositions memory) {\n// // The sideNode at this level is the node at position nextInsertIndex - 1, and only when this level\n// // is live (nextInsertIndex is odd). For a single-leaf update the one node we recompute (`node`, at\n// // position nodeIndex) is that sideNode exactly when nodeIndex == nextInsertIndex - 1. Write the result\n// // into the struct so the caller sees it; reset the flag each level since `lvlPos` is reused.\n// if (lvlPos.nextInsertIndex & 1 == 1 && (lvlPos.nextInsertIndex - 1) == lvlPos.nodeIndex) {\n// lvlPos.newSideNode = node;\n// lvlPos.isNewSideNode = true;\n// } else {\n// lvlPos.isNewSideNode = false;\n// }\n// if (lvlPos.nodeIndex & 1 == 1) {\n// node = hasher([proofSiblings[lvlPos.siblingIndex], node]);\n// unchecked {\n// ++lvlPos.siblingIndex;\n// }\n// } else {\n// // make sure node index is not at the edge @TODO explain\n// if (lvlPos.nodeIndex != lvlPos.edgeIndex) {\n// node = hasher([node, proofSiblings[lvlPos.siblingIndex]]);\n\n// unchecked {\n// ++lvlPos.siblingIndex;\n// }\n// }\n// }\n\n// lvlPos.nodeIndex >>= 1;\n// lvlPos.edgeIndex >>= 1;\n// lvlPos.nextInsertIndex >>= 1;\n\n// return (node, lvlPos);\n// }\n\n// /// @dev Hashes merkle proof and returns the root the leaf belongs to\n// /// @param leafIndex: The leaf to proof inclusion of\n// /// @param leafIndex: The index of the leaf within the tree.\n// /// @param proofSiblings: The sibling nodes along the path from the leaf to the root.\n// /// @return The root obtained from hashing the leaf with the provided siblings.\n// /// @notice Contracts using this function with snark based hash functions,\n// /// need to check that the leaf and proofSiblings are within the snark scalar field.\n// function _proofToRoot(\n// uint256 treeDepth,\n// uint256 treeSize,\n// uint256 leaf,\n// uint256 leafIndex,\n// uint256[] calldata proofSiblings,\n// function(uint256[2] memory) view returns (uint256) hasher\n// ) internal view returns (uint256) {\n// if (treeSize == 0) {\n// revert TreeEmpty();\n// }\n\n// uint256 node = leaf;\n// ProofLevelPositions memory lvlPos = ProofLevelPositions(\n// leafIndex, // nodeIndex\n// // index of the very last leaf in the tree\n// // tracking this index up the tree, follows the indexes of the nodes in self.sidNodes\n// treeSize - 1, // edgeIndex\n// // index of the next insert in the tree, tracking this up to tree to determine\n// // what sideNode is needed to store\n// treeSize, // nextInsertIndex\n// // because leanIMT is not balanced proofSiblings.length can be smaller then tree depth\n// // we cant just use level so we separately track those 2\n// 0, // proofSiblingReadIndex\n// 0, // newSideNode\n// false // isNewSideNode\n// );\n// for (uint256 level = 0; level < treeDepth; ) {\n// // no need for sideNodes so trackSideNodes=false\n// (node, lvlPos) = _hashProofLevel(node, lvlPos, proofSiblings, hasher);\n\n// unchecked {\n// ++level;\n// }\n// }\n// return node;\n// }\n//---------------------------------------------------------------------------------------------------------------------\n"
225
+ },
226
+ "npm/@warptoad/skinny-imt.sol@0.0.11/InternalSkinnyIMTEvent.sol": {
227
+ "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.4;\n\nimport {InternalSkinnyIMTCore, MultiProof, TreeEmpty} from \"./InternalSkinnyIMTCore.sol\";\nimport {SkinnyIMTData as SkinnyIMTDataEvent} from \"./InternalSkinnyIMTCore.sol\";\nimport {IIMTEvents} from \"./interfaces/IIMTEvents.sol\";\nimport {_emitUpdatedMany, _requireInField, _requireAllInField} from \"./SkinnyIMTUtils.sol\";\n\nerror NotInitialized();\nerror AlreadyInitialized();\n\nlibrary InternalSkinnyIMTEvent {\n function _reset(SkinnyIMTDataEvent storage self) internal {\n uint256 id = self.treeId;\n emit IIMTEvents.NewRoot(id, 0, 0);\n InternalSkinnyIMTCore._reset(self);\n }\n\n /// @dev Checks whether the tree has been initialized.\n /// @param self: A storage reference to the 'SkinnyIMTDataEvent' struct.\n /// @return True if the tree has been initialized, false otherwise.\n function _isInitialized(SkinnyIMTDataEvent storage self) internal view returns (bool) {\n return self.treeId != 0;\n }\n\n /// @dev Initializes the tree by assigning it a non-zero `treeId` derived from its storage slot.\n /// Reverts if the tree has already been initialized.\n /// @param self: A storage reference to the 'SkinnyIMTDataEvent' struct.\n /// @return The newly assigned tree id.\n function _init(SkinnyIMTDataEvent storage self) internal returns (uint256) {\n if (_isInitialized(self)) {\n revert AlreadyInitialized();\n }\n uint256 slot;\n assembly {\n slot := self.slot\n }\n uint256 id = slot + 1;\n self.treeId = id;\n emit IIMTEvents.NewTree(id);\n emit IIMTEvents.NewRoot(id, 0, 0);\n return id;\n }\n\n function _getSideNodes(\n SkinnyIMTDataEvent storage self,\n uint256 firstIndex,\n uint256 endIndex\n ) internal view returns (uint256[] memory) {\n uint256[] memory sideNodes = new uint256[](endIndex - firstIndex);\n for (uint256 i = 0; i < sideNodes.length; i++) {\n sideNodes[i] = self.sideNodes[firstIndex + i];\n }\n return sideNodes;\n }\n\n function _getRepeatedHashes(\n SkinnyIMTDataEvent storage self,\n uint256 firstIndex,\n uint256 endIndex\n ) internal view returns (uint256[] memory) {\n uint256[] memory hashes = new uint256[](endIndex - firstIndex);\n for (uint256 i = 0; i < hashes.length; i++) {\n hashes[i] = self.repeatedHashCache[firstIndex + i];\n }\n return hashes;\n }\n\n function _insert(\n SkinnyIMTDataEvent storage self,\n uint256 leaf,\n function(uint256[2] memory) view returns (uint256) hasher\n ) internal returns (uint256, uint256) {\n // update tree\n (uint256 newRoot, uint256 index) = InternalSkinnyIMTCore._insert(self, leaf, hasher);\n // emit IIMTEvents.event\n uint256 treeId = self.treeId;\n if (treeId == 0) {\n revert NotInitialized();\n }\n emit IIMTEvents.NewLeaf(treeId, index, leaf);\n emit IIMTEvents.NewRoot(treeId, newRoot, self.size);\n return (newRoot, index);\n }\n\n function _insertBN254(\n SkinnyIMTDataEvent storage self,\n uint256 leaf,\n function(uint256[2] memory) view returns (uint256) hasher\n ) internal returns (uint256, uint256) {\n // field check\n _requireInField(leaf);\n // update tree\n (uint256 newRoot, uint256 index) = InternalSkinnyIMTCore._insert(self, leaf, hasher);\n // emit IIMTEvents.event\n uint256 treeId = self.treeId;\n if (treeId == 0) {\n revert NotInitialized();\n }\n emit IIMTEvents.NewLeaf(treeId, index, leaf);\n emit IIMTEvents.NewRoot(treeId, newRoot, self.size);\n return (newRoot, index);\n }\n\n function _insertMany(\n SkinnyIMTDataEvent storage self,\n uint256[] calldata leaves,\n function(uint256[2] memory) view returns (uint256) hasher\n ) internal returns (uint256, uint256, uint256) {\n // update tree\n (uint256 newRoot, uint256 startIndex, uint256 nextIndex) = InternalSkinnyIMTCore._insertMany(\n self,\n leaves,\n hasher\n );\n\n // emit IIMTEvents.events\n uint256 treeId = self.treeId;\n if (treeId == 0) {\n revert NotInitialized();\n }\n for (uint256 i = 0; i < leaves.length; ) {\n uint256 leaf = leaves[i];\n emit IIMTEvents.NewLeaf(treeId, startIndex + i, leaf);\n unchecked {\n ++i;\n }\n }\n emit IIMTEvents.NewRoot(treeId, newRoot, nextIndex);\n return (newRoot, startIndex, nextIndex);\n }\n\n function _insertManyBN254(\n SkinnyIMTDataEvent storage self,\n uint256[] calldata leaves,\n function(uint256[2] memory) view returns (uint256) hasher\n ) internal returns (uint256, uint256, uint256) {\n // update tree\n (uint256 newRoot, uint256 startIndex, uint256 nextIndex) = InternalSkinnyIMTCore._insertMany(\n self,\n leaves,\n hasher\n );\n\n // emit IIMTEvents.events\n uint256 treeId = self.treeId;\n if (treeId == 0) {\n revert NotInitialized();\n }\n for (uint256 i = 0; i < leaves.length; ) {\n uint256 leaf = leaves[i];\n _requireInField(leaf);\n emit IIMTEvents.NewLeaf(treeId, startIndex + i, leaf);\n unchecked {\n ++i;\n }\n }\n emit IIMTEvents.NewRoot(treeId, newRoot, nextIndex);\n return (newRoot, startIndex, nextIndex);\n }\n\n function _insertManyRepeated(\n SkinnyIMTDataEvent storage self,\n uint256 value,\n uint256 amount,\n function(uint256[2] memory) view returns (uint256) hasher\n ) internal returns (uint256, uint256, uint256) {\n // update tree (Core returns the authoritative start/next indexes)\n (uint256 newRoot, uint256 startIndex, uint256 nextIndex) = InternalSkinnyIMTCore._insertManyRepeated(\n self,\n value,\n amount,\n hasher\n );\n // emit IIMTEvents.event\n uint256 treeId = self.treeId;\n if (treeId == 0) {\n revert NotInitialized();\n }\n emit IIMTEvents.RepeatedLeafs(treeId, startIndex, nextIndex, value);\n emit IIMTEvents.NewRoot(treeId, newRoot, nextIndex);\n return (newRoot, startIndex, nextIndex);\n }\n\n function _insertManyRepeatedBN254(\n SkinnyIMTDataEvent storage self,\n uint256 value,\n uint256 amount,\n function(uint256[2] memory) view returns (uint256) hasher\n ) internal returns (uint256, uint256, uint256) {\n // check\n _requireInField(value);\n // update tree (Core returns the authoritative start/next indexes)\n (uint256 newRoot, uint256 startIndex, uint256 nextIndex) = InternalSkinnyIMTCore._insertManyRepeated(\n self,\n value,\n amount,\n hasher\n );\n // emit IIMTEvents.event\n uint256 treeId = self.treeId;\n if (treeId == 0) {\n revert NotInitialized();\n }\n emit IIMTEvents.RepeatedLeafs(treeId, startIndex, nextIndex, value);\n emit IIMTEvents.NewRoot(treeId, newRoot, nextIndex);\n return (newRoot, startIndex, nextIndex);\n }\n\n function _precomputeRepeatedCache(\n SkinnyIMTDataEvent storage self,\n uint256 value,\n uint256 upToLevel,\n function(uint256[2] memory) view returns (uint256) hasher\n ) internal {\n // precompute emits no event, so it never reads treeId; guard init explicitly (rare op, cost irrelevant)\n if (self.treeId == 0) {\n revert NotInitialized();\n }\n // update cache\n InternalSkinnyIMTCore._precomputeRepeatedCache(self, value, upToLevel, hasher);\n }\n\n function _precomputeRepeatedCacheBN254(\n SkinnyIMTDataEvent storage self,\n uint256 value,\n uint256 upToLevel,\n function(uint256[2] memory) view returns (uint256) hasher\n ) internal {\n // precompute emits no event, so it never reads treeId; guard init explicitly (rare op, cost irrelevant)\n if (self.treeId == 0) {\n revert NotInitialized();\n }\n // check\n _requireInField(value);\n // update cache\n InternalSkinnyIMTCore._precomputeRepeatedCache(self, value, upToLevel, hasher);\n }\n\n function _update(\n SkinnyIMTDataEvent storage self,\n uint256 oldLeaf,\n uint256 newLeaf,\n uint256 leafIndex,\n uint256[] calldata proofSiblings,\n function(uint256[2] memory) view returns (uint256) hasher\n ) internal returns (uint256) {\n // update tree\n uint256 newRoot = InternalSkinnyIMTCore._update(self, oldLeaf, newLeaf, leafIndex, proofSiblings, hasher);\n // emit IIMTEvents.event\n uint256 treeId = self.treeId;\n if (treeId == 0) {\n revert NotInitialized();\n }\n emit IIMTEvents.UpdatedLeaf(treeId, leafIndex, newLeaf, oldLeaf);\n emit IIMTEvents.NewRoot(treeId, newRoot, self.size);\n return newRoot;\n }\n\n function _updateBN254(\n SkinnyIMTDataEvent storage self,\n uint256 oldLeaf,\n uint256 newLeaf,\n uint256 leafIndex,\n uint256[] calldata proofSiblings,\n function(uint256[2] memory) view returns (uint256) hasher\n ) internal returns (uint256) {\n // check\n _requireInField(newLeaf);\n _requireAllInField(proofSiblings);\n // update tree\n uint256 newRoot = InternalSkinnyIMTCore._update(self, oldLeaf, newLeaf, leafIndex, proofSiblings, hasher);\n // emit IIMTEvents.event\n uint256 treeId = self.treeId;\n if (treeId == 0) {\n revert NotInitialized();\n }\n emit IIMTEvents.UpdatedLeaf(treeId, leafIndex, newLeaf, oldLeaf);\n emit IIMTEvents.NewRoot(treeId, newRoot, self.size);\n return newRoot;\n }\n\n function _updateMany(\n SkinnyIMTDataEvent storage self,\n uint256[] calldata oldLeaves,\n uint256[] calldata newLeaves,\n uint256[] calldata leafIndexes,\n uint256[] calldata proofSiblings,\n function(uint256[2] memory) view returns (uint256) hasher\n ) internal returns (uint256) {\n // check\n if (self.size == 0) {\n revert TreeEmpty();\n }\n\n // update tree\n // depth/edgeIndex come from the live tree, never the caller. Built into a local (and the\n // emit IIMTEvents.loop split into a helper) to keep this frame under the stack-too-deep limit without viaIR.\n MultiProof memory proof = MultiProof(self.depth, self.size - 1, leafIndexes, proofSiblings);\n uint256 newRoot = InternalSkinnyIMTCore._updateMany(self, oldLeaves, newLeaves, proof, hasher);\n // emit IIMTEvents.event\n // no tree.id == 0 check here, self.size == 0 already does that, also stack limit is too tight\n _emitUpdatedMany(self.treeId, leafIndexes, oldLeaves, newLeaves);\n emit IIMTEvents.NewRoot(self.treeId, newRoot, self.size);\n return newRoot;\n }\n\n function _updateManyBN254(\n SkinnyIMTDataEvent storage self,\n uint256[] calldata oldLeaves,\n uint256[] calldata newLeaves,\n uint256[] calldata leafIndexes,\n uint256[] calldata proofSiblings,\n function(uint256[2] memory) view returns (uint256) hasher\n ) internal returns (uint256) {\n // check\n if (self.size == 0) {\n revert TreeEmpty();\n }\n _requireAllInField(newLeaves);\n _requireAllInField(proofSiblings);\n\n // update tree\n // depth/edgeIndex come from the live tree, never the caller. Built into a local (and the\n // emit IIMTEvents.loop split into a helper) to keep this frame under the stack-too-deep limit without viaIR.\n MultiProof memory proof = MultiProof(self.depth, self.size - 1, leafIndexes, proofSiblings);\n uint256 newRoot = InternalSkinnyIMTCore._updateMany(self, oldLeaves, newLeaves, proof, hasher);\n // emit IIMTEvents.event\n // no tree.id == 0 check here, self.size == 0 already does that, also stack limit is too tight\n _emitUpdatedMany(self.treeId, leafIndexes, oldLeaves, newLeaves);\n emit IIMTEvents.NewRoot(self.treeId, newRoot, self.size);\n return newRoot;\n }\n\n function _root(SkinnyIMTDataEvent storage self) internal view returns (uint256) {\n return InternalSkinnyIMTCore._root(self);\n }\n\n function _proofToRoot(\n uint256 treeDepth,\n uint256 treeSize,\n uint256 leaf,\n uint256 leafIndex,\n uint256[] calldata proofSiblings,\n function(uint256[2] memory) view returns (uint256) hasher\n ) internal view returns (uint256) {\n // verify\n return InternalSkinnyIMTCore._proofToRoot(treeDepth, treeSize, leaf, leafIndex, proofSiblings, hasher);\n }\n\n function _proofToRootBN254(\n uint256 treeDepth,\n uint256 treeSize,\n uint256 leaf,\n uint256 leafIndex,\n uint256[] calldata proofSiblings,\n function(uint256[2] memory) view returns (uint256) hasher\n ) internal view returns (uint256) {\n // check\n _requireInField(leaf);\n _requireAllInField(proofSiblings);\n // verify\n return InternalSkinnyIMTCore._proofToRoot(treeDepth, treeSize, leaf, leafIndex, proofSiblings, hasher);\n }\n\n function _proofManyToRoot(\n uint256 treeDepth,\n uint256 treeSize,\n uint256[] calldata leaves,\n uint256[] calldata leafIndexes,\n uint256[] calldata proofSiblings,\n function(uint256[2] memory) view returns (uint256) hasher\n ) internal view returns (uint256) {\n // takes treeSize (not edgeIndex) to match _proofToRoot; the core wants edgeIndex == treeSize - 1\n if (treeSize == 0) {\n revert TreeEmpty();\n }\n // verify\n return\n InternalSkinnyIMTCore._proofManyToRoot(\n leaves,\n MultiProof(treeDepth, treeSize - 1, leafIndexes, proofSiblings),\n hasher\n );\n }\n\n function _proofManyToRootBN254(\n uint256 treeDepth,\n uint256 treeSize,\n uint256[] calldata leaves,\n uint256[] calldata leafIndexes,\n uint256[] calldata proofSiblings,\n function(uint256[2] memory) view returns (uint256) hasher\n ) internal view returns (uint256) {\n // takes treeSize (not edgeIndex) to match _proofToRoot; the core wants edgeIndex == treeSize - 1\n if (treeSize == 0) {\n revert TreeEmpty();\n }\n // check\n _requireAllInField(leaves);\n _requireAllInField(proofSiblings);\n // verify\n return\n InternalSkinnyIMTCore._proofManyToRoot(\n leaves,\n MultiProof(treeDepth, treeSize - 1, leafIndexes, proofSiblings),\n hasher\n );\n }\n}\n"
228
+ },
229
+ "npm/@warptoad/skinny-imt.sol@0.0.11/InternalSkinnyIMTStorage.sol": {
230
+ "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.4;\n\nimport {InternalSkinnyIMTEvent, SkinnyIMTDataEvent} from \"./InternalSkinnyIMTEvent.sol\";\nimport {IIMTEvents} from \"./interfaces/IIMTEvents.sol\";\nimport {_emitUpdatedMany, _requireInField, _requireAllInField} from \"./SkinnyIMTUtils.sol\";\n\n// added storage of the leaves to allow syncing with full nodes for leaves older then 1 year\nstruct SkinnyIMTDataStorage {\n // arrays cost more but store in consecutive slots which allows for usage of debug_storageRangeAt\n // to read this extremely fast\n uint256[] leaves;\n SkinnyIMTDataEvent treeData;\n}\n\nlibrary InternalSkinnyIMTStorage {\n function _reset(SkinnyIMTDataStorage storage self) internal {\n // the Storage variant also stores leaves in a pushed array, so it must be cleared here;\n // InternalSkinnyIMTEvent._reset only zeroes size/depth in the core.\n delete self.leaves;\n InternalSkinnyIMTEvent._reset(self.treeData);\n }\n\n /// helper function for clients that don't have debug_storageRangeAt\n /// @param self: A storage reference to the 'SkinnyIMTDataStorage' struct.\n /// @param firstIndex: first leaf index to get (inclusive)\n /// @param endIndex: last leaf index to stop retrieving at (exclusive)\n function _getLeaves(\n SkinnyIMTDataStorage storage self,\n uint256 firstIndex,\n uint256 endIndex\n ) internal view returns (uint256[] memory) {\n uint256[] memory leaves = new uint256[](endIndex - firstIndex);\n for (uint256 i = 0; i < leaves.length; i++) {\n leaves[i] = self.leaves[firstIndex + i];\n }\n return leaves;\n }\n\n function _getSideNodes(\n SkinnyIMTDataStorage storage self,\n uint256 firstIndex,\n uint256 endIndex\n ) internal view returns (uint256[] memory) {\n return InternalSkinnyIMTEvent._getSideNodes(self.treeData, firstIndex, endIndex);\n }\n\n function _getRepeatedHashes(\n SkinnyIMTDataStorage storage self,\n uint256 firstIndex,\n uint256 endIndex\n ) internal view returns (uint256[] memory) {\n return InternalSkinnyIMTEvent._getRepeatedHashes(self.treeData, firstIndex, endIndex);\n }\n\n function _init(SkinnyIMTDataStorage storage self) internal returns (uint256) {\n return InternalSkinnyIMTEvent._init(self.treeData);\n }\n\n function _insert(\n SkinnyIMTDataStorage storage self,\n uint256 leaf,\n function(uint256[2] memory) view returns (uint256) hasher\n ) internal returns (uint256, uint256) {\n self.leaves.push(leaf);\n return InternalSkinnyIMTEvent._insert(self.treeData, leaf, hasher);\n }\n\n function _insertBN254(\n SkinnyIMTDataStorage storage self,\n uint256 leaf,\n function(uint256[2] memory) view returns (uint256) hasher\n ) internal returns (uint256, uint256) {\n self.leaves.push(leaf);\n return InternalSkinnyIMTEvent._insertBN254(self.treeData, leaf, hasher);\n }\n\n function _insertMany(\n SkinnyIMTDataStorage storage self,\n uint256[] calldata leaves,\n function(uint256[2] memory) view returns (uint256) hasher\n ) internal returns (uint256, uint256, uint256) {\n for (uint256 i = 0; i < leaves.length; i++) {\n self.leaves.push(leaves[i]);\n }\n return InternalSkinnyIMTEvent._insertMany(self.treeData, leaves, hasher);\n }\n\n function _insertManyBN254(\n SkinnyIMTDataStorage storage self,\n uint256[] calldata leaves,\n function(uint256[2] memory) view returns (uint256) hasher\n ) internal returns (uint256, uint256, uint256) {\n for (uint256 i = 0; i < leaves.length; i++) {\n self.leaves.push(leaves[i]);\n }\n return InternalSkinnyIMTEvent._insertManyBN254(self.treeData, leaves, hasher);\n }\n\n function _insertManyRepeated(\n SkinnyIMTDataStorage storage self,\n uint256 value,\n uint256 amount,\n function(uint256[2] memory) view returns (uint256) hasher\n ) internal returns (uint256, uint256, uint256) {\n uint256 treeSize = self.treeData.size;\n for (uint256 i = 0; i < amount; i++) {\n self.leaves.push(value);\n emit IIMTEvents.NewLeaf(self.treeData.treeId, treeSize + i, value);\n }\n return InternalSkinnyIMTEvent._insertManyRepeated(self.treeData, value, amount, hasher);\n }\n\n function _insertManyRepeatedBN254(\n SkinnyIMTDataStorage storage self,\n uint256 value,\n uint256 amount,\n function(uint256[2] memory) view returns (uint256) hasher\n ) internal returns (uint256, uint256, uint256) {\n uint256 treeSize = self.treeData.size;\n for (uint256 i = 0; i < amount; i++) {\n self.leaves.push(value);\n emit IIMTEvents.NewLeaf(self.treeData.treeId, treeSize + i, value);\n }\n return InternalSkinnyIMTEvent._insertManyRepeatedBN254(self.treeData, value, amount, hasher);\n }\n\n function _precomputeRepeatedCache(\n SkinnyIMTDataStorage storage self,\n uint256 value,\n uint256 upToLevel,\n function(uint256[2] memory) view returns (uint256) hasher\n ) internal {\n return InternalSkinnyIMTEvent._precomputeRepeatedCache(self.treeData, value, upToLevel, hasher);\n }\n\n function _precomputeRepeatedCacheBN254(\n SkinnyIMTDataStorage storage self,\n uint256 value,\n uint256 upToLevel,\n function(uint256[2] memory) view returns (uint256) hasher\n ) internal {\n return InternalSkinnyIMTEvent._precomputeRepeatedCacheBN254(self.treeData, value, upToLevel, hasher);\n }\n\n function _update(\n SkinnyIMTDataStorage storage self,\n uint256 oldLeaf,\n uint256 newLeaf,\n uint256 leafIndex,\n uint256[] calldata proofSiblings,\n function(uint256[2] memory) view returns (uint256) hasher\n ) internal returns (uint256) {\n self.leaves[leafIndex] = newLeaf;\n return InternalSkinnyIMTEvent._update(self.treeData, oldLeaf, newLeaf, leafIndex, proofSiblings, hasher);\n }\n\n function _updateBN254(\n SkinnyIMTDataStorage storage self,\n uint256 oldLeaf,\n uint256 newLeaf,\n uint256 leafIndex,\n uint256[] calldata proofSiblings,\n function(uint256[2] memory) view returns (uint256) hasher\n ) internal returns (uint256) {\n self.leaves[leafIndex] = newLeaf;\n return InternalSkinnyIMTEvent._updateBN254(self.treeData, oldLeaf, newLeaf, leafIndex, proofSiblings, hasher);\n }\n\n function _updateMany(\n SkinnyIMTDataStorage storage self,\n uint256[] calldata oldLeaves,\n uint256[] calldata newLeaves,\n uint256[] calldata leafIndexes,\n uint256[] calldata proofSiblings,\n function(uint256[2] memory) view returns (uint256) hasher\n ) internal returns (uint256) {\n for (uint256 i = 0; i < newLeaves.length; i++) {\n self.leaves[leafIndexes[i]] = newLeaves[i];\n }\n return\n InternalSkinnyIMTEvent._updateMany(self.treeData, oldLeaves, newLeaves, leafIndexes, proofSiblings, hasher);\n }\n\n function _updateManyBN254(\n SkinnyIMTDataStorage storage self,\n uint256[] calldata oldLeaves,\n uint256[] calldata newLeaves,\n uint256[] calldata leafIndexes,\n uint256[] calldata proofSiblings,\n function(uint256[2] memory) view returns (uint256) hasher\n ) internal returns (uint256) {\n for (uint256 i = 0; i < newLeaves.length; i++) {\n self.leaves[leafIndexes[i]] = newLeaves[i];\n }\n return\n InternalSkinnyIMTEvent._updateManyBN254(\n self.treeData,\n oldLeaves,\n newLeaves,\n leafIndexes,\n proofSiblings,\n hasher\n );\n }\n\n function _root(SkinnyIMTDataStorage storage self) internal view returns (uint256) {\n return InternalSkinnyIMTEvent._root(self.treeData);\n }\n\n function _proofToRoot(\n uint256 treeDepth,\n uint256 treeSize,\n uint256 leaf,\n uint256 leafIndex,\n uint256[] calldata proofSiblings,\n function(uint256[2] memory) view returns (uint256) hasher\n ) internal view returns (uint256) {\n return InternalSkinnyIMTEvent._proofToRoot(treeDepth, treeSize, leaf, leafIndex, proofSiblings, hasher);\n }\n\n function _proofToRootBN254(\n uint256 treeDepth,\n uint256 treeSize,\n uint256 leaf,\n uint256 leafIndex,\n uint256[] calldata proofSiblings,\n function(uint256[2] memory) view returns (uint256) hasher\n ) internal view returns (uint256) {\n return InternalSkinnyIMTEvent._proofToRootBN254(treeDepth, treeSize, leaf, leafIndex, proofSiblings, hasher);\n }\n\n function _proofManyToRoot(\n uint256 treeDepth,\n uint256 edgeIndex,\n uint256[] calldata leaves,\n uint256[] calldata leafIndexes,\n uint256[] calldata proofSiblings,\n function(uint256[2] memory) view returns (uint256) hasher\n ) internal view returns (uint256) {\n return\n InternalSkinnyIMTEvent._proofManyToRoot(treeDepth, edgeIndex, leaves, leafIndexes, proofSiblings, hasher);\n }\n\n function _proofManyToRootBN254(\n uint256 treeDepth,\n uint256 edgeIndex,\n uint256[] calldata leaves,\n uint256[] calldata leafIndexes,\n uint256[] calldata proofSiblings,\n function(uint256[2] memory) view returns (uint256) hasher\n ) internal view returns (uint256) {\n return\n InternalSkinnyIMTEvent._proofManyToRootBN254(\n treeDepth,\n edgeIndex,\n leaves,\n leafIndexes,\n proofSiblings,\n hasher\n );\n }\n}\n"
231
+ },
232
+ "npm/@warptoad/skinny-imt.sol@0.0.11/poseidon2/SkinnyIMTPoseidon2Read.sol": {
233
+ "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.4;\n\nimport {LibPoseidon2Yul} from \"poseidon2-evm/src/bn254/yul/LibPoseidon2Yul.sol\";\n\nimport {InternalSkinnyIMTEvent, SkinnyIMTDataEvent} from \"../InternalSkinnyIMTEvent.sol\";\nimport {TreeEmpty} from \"../InternalSkinnyIMTCore.sol\";\n\n/// @title SkinnyIMTPoseidon2Read\n/// @notice Stateless proof verification (`proofToRoot` / `proofManyToRoot`) split out of\n/// `SkinnyIMTPoseidon2WriteEvent` and `SkinnyIMTPoseidon2WriteStorage` to keep those libraries under the\n/// EIP-170 contract size limit. Both functions take the whole proof as parameters and touch no\n/// storage, so a single library serves the plain and full-node trees alike.\nlibrary SkinnyIMTPoseidon2Read {\n function hasher(uint256[2] memory leaves) public pure returns (uint256) {\n return LibPoseidon2Yul.hash_2(leaves[0], leaves[1]);\n }\n\n function root(SkinnyIMTDataEvent storage self) public view returns (uint256) {\n return InternalSkinnyIMTEvent._root(self);\n }\n\n function proofToRootBN254(\n uint256 treeDepth,\n uint256 treeSize,\n uint256 leaf,\n uint256 leafIndex,\n uint256[] calldata proofSiblings\n ) public view returns (uint256) {\n return InternalSkinnyIMTEvent._proofToRootBN254(treeDepth, treeSize, leaf, leafIndex, proofSiblings, hasher);\n }\n\n function proofManyToRootBN254(\n uint256 treeDepth,\n uint256 treeSize,\n uint256[] calldata leaves,\n uint256[] calldata leafIndexes,\n uint256[] calldata proofSiblings\n ) public view returns (uint256) {\n return\n InternalSkinnyIMTEvent._proofManyToRootBN254(\n treeDepth,\n treeSize,\n leaves,\n leafIndexes,\n proofSiblings,\n hasher\n );\n }\n\n function verify(\n SkinnyIMTDataEvent storage self,\n uint256 leaf,\n uint256 leafIndex,\n uint256[] calldata proofSiblings\n ) public view returns (bool) {\n if (self.size == 0) {\n revert TreeEmpty();\n }\n uint256 provenRoot = InternalSkinnyIMTEvent._proofToRootBN254(\n self.depth,\n self.size,\n leaf,\n leafIndex,\n proofSiblings,\n hasher\n );\n uint256 currentRoot = InternalSkinnyIMTEvent._root(self);\n return provenRoot == currentRoot;\n }\n\n function verifyMany(\n SkinnyIMTDataEvent storage self,\n uint256[] calldata leaves,\n uint256[] calldata leafIndexes,\n uint256[] calldata proofSiblings\n ) public view returns (bool) {\n if (self.size == 0) {\n revert TreeEmpty();\n }\n uint256 provenRoot = InternalSkinnyIMTEvent._proofManyToRootBN254(\n self.depth,\n self.size,\n leaves,\n leafIndexes,\n proofSiblings,\n hasher\n );\n uint256 currentRoot = InternalSkinnyIMTEvent._root(self);\n return provenRoot == currentRoot;\n }\n}\n"
234
+ },
235
+ "npm/@warptoad/skinny-imt.sol@0.0.11/poseidon2/SkinnyIMTPoseidon2WriteEvent.sol": {
236
+ "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.4;\n\nimport {LibPoseidon2Yul} from \"poseidon2-evm/src/bn254/yul/LibPoseidon2Yul.sol\";\nimport {InternalSkinnyIMTEvent, SkinnyIMTDataEvent} from \"../InternalSkinnyIMTEvent.sol\";\n\nlibrary SkinnyIMTPoseidon2WriteEvent {\n function hasher(uint256[2] memory leaves) private pure returns (uint256) {\n return LibPoseidon2Yul.hash_2(leaves[0], leaves[1]);\n }\n\n function init(SkinnyIMTDataEvent storage self) public returns (uint256) {\n return InternalSkinnyIMTEvent._init(self);\n }\n\n function reset(SkinnyIMTDataEvent storage self) internal {\n InternalSkinnyIMTEvent._reset(self);\n }\n\n function insert(SkinnyIMTDataEvent storage self, uint256 leaf) public returns (uint256, uint256) {\n return InternalSkinnyIMTEvent._insertBN254(self, leaf, hasher);\n }\n\n function insertMany(\n SkinnyIMTDataEvent storage self,\n uint256[] calldata leaves\n ) public returns (uint256, uint256, uint256) {\n return InternalSkinnyIMTEvent._insertManyBN254(self, leaves, hasher);\n }\n\n function insertManyRepeated(\n SkinnyIMTDataEvent storage self,\n uint256 value,\n uint256 amount\n ) public returns (uint256, uint256, uint256) {\n return InternalSkinnyIMTEvent._insertManyRepeatedBN254(self, value, amount, hasher);\n }\n\n function precomputeRepeatedCache(SkinnyIMTDataEvent storage self, uint256 value, uint256 upToLevel) internal {\n return InternalSkinnyIMTEvent._precomputeRepeatedCacheBN254(self, value, upToLevel, hasher);\n }\n\n function update(\n SkinnyIMTDataEvent storage self,\n uint256 oldLeaf,\n uint256 newLeaf,\n uint256 leafIndex,\n uint256[] calldata proofSiblings\n ) public returns (uint256) {\n return InternalSkinnyIMTEvent._updateBN254(self, oldLeaf, newLeaf, leafIndex, proofSiblings, hasher);\n }\n\n function updateMany(\n SkinnyIMTDataEvent storage self,\n uint256[] calldata oldLeaves,\n uint256[] calldata newLeaves,\n uint256[] calldata leafIndexes,\n uint256[] calldata proofSiblings\n ) public returns (uint256) {\n return InternalSkinnyIMTEvent._updateManyBN254(self, oldLeaves, newLeaves, leafIndexes, proofSiblings, hasher);\n }\n}\n"
237
+ },
238
+ "npm/@warptoad/skinny-imt.sol@0.0.11/poseidon2/SkinnyIMTPoseidon2WriteStorage.sol": {
239
+ "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.4;\n\nimport {LibPoseidon2Yul} from \"poseidon2-evm/src/bn254/yul/LibPoseidon2Yul.sol\";\nimport {InternalSkinnyIMTStorage, SkinnyIMTDataStorage} from \"../InternalSkinnyIMTStorage.sol\";\n\nlibrary SkinnyIMTPoseidon2WriteStorage {\n // Kept private: only used internally as a function pointer (inlining is the optimal call path).\n // getSkinnyLeaves is intentionally NOT exposed here; inherit SkinnyIMTReadableStorage for that.\n function hasher(uint256[2] memory leaves) private pure returns (uint256) {\n return LibPoseidon2Yul.hash_2(leaves[0], leaves[1]);\n }\n\n function init(SkinnyIMTDataStorage storage self) public returns (uint256) {\n return InternalSkinnyIMTStorage._init(self);\n }\n\n function reset(SkinnyIMTDataStorage storage self) internal {\n InternalSkinnyIMTStorage._reset(self);\n }\n\n function insert(SkinnyIMTDataStorage storage self, uint256 leaf) public returns (uint256, uint256) {\n return InternalSkinnyIMTStorage._insertBN254(self, leaf, hasher);\n }\n\n function insertMany(\n SkinnyIMTDataStorage storage self,\n uint256[] calldata leaves\n ) public returns (uint256, uint256, uint256) {\n return InternalSkinnyIMTStorage._insertManyBN254(self, leaves, hasher);\n }\n\n function insertManyRepeated(\n SkinnyIMTDataStorage storage self,\n uint256 value,\n uint256 amount\n ) public returns (uint256, uint256, uint256) {\n return InternalSkinnyIMTStorage._insertManyRepeatedBN254(self, value, amount, hasher);\n }\n\n function precomputeRepeatedCache(SkinnyIMTDataStorage storage self, uint256 value, uint256 upToLevel) internal {\n return InternalSkinnyIMTStorage._precomputeRepeatedCacheBN254(self, value, upToLevel, hasher);\n }\n\n function update(\n SkinnyIMTDataStorage storage self,\n uint256 oldLeaf,\n uint256 newLeaf,\n uint256 leafIndex,\n uint256[] calldata proofSiblings\n ) public returns (uint256) {\n return InternalSkinnyIMTStorage._updateBN254(self, oldLeaf, newLeaf, leafIndex, proofSiblings, hasher);\n }\n\n function updateMany(\n SkinnyIMTDataStorage storage self,\n uint256[] calldata oldLeaves,\n uint256[] calldata newLeaves,\n uint256[] calldata leafIndexes,\n uint256[] calldata proofSiblings\n ) public returns (uint256) {\n return\n InternalSkinnyIMTStorage._updateManyBN254(self, oldLeaves, newLeaves, leafIndexes, proofSiblings, hasher);\n }\n}\n"
240
+ },
241
+ "npm/@warptoad/skinny-imt.sol@0.0.11/SkinnyIMTReadableEvent.sol": {
242
+ "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.20;\n\nimport {SkinnyIMTDataEvent, InternalSkinnyIMTEvent} from \"./InternalSkinnyIMTEvent.sol\";\nimport {NotInitialized} from \"./InternalSkinnyIMTEvent.sol\";\nimport {ERC165} from \"@openzeppelin/contracts/utils/introspection/ERC165.sol\";\nimport {IERC165} from \"@openzeppelin/contracts/utils/introspection/IERC165.sol\";\nimport {ISkinnyIMTReadableEvent} from \"./interfaces/ISkinnyIMTReadableEvent.sol\";\n\n/// @title SkinnyIMTReadableEvent\n/// @dev inheritable interface so any contract with a skinny tree has a common interface for clients side libs to read\n///\n/// The event variant keeps no leaves — only the side nodes it needs to insert — so there is no leaf\n/// reader and no base-slot reader here: nothing lives in consecutive slots for a client to read raw.\n/// A consumer that stores its leaves inherits `SkinnyIMTReadableStorage` instead.\nabstract contract SkinnyIMTReadableEvent is ERC165, ISkinnyIMTReadableEvent {\n /// @dev Resolves `treeId` to the consumer's tree storage. Single-tree consumers may ignore `treeId`.\n function _getSkinnyEventTree(uint256 treeId) internal view virtual returns (SkinnyIMTDataEvent storage);\n\n function _initializedSkinnyEventTree(uint256 treeId) internal view returns (SkinnyIMTDataEvent storage) {\n SkinnyIMTDataEvent storage tree = _getSkinnyEventTree(treeId);\n if (tree.treeId == 0) {\n revert NotInitialized();\n }\n return tree;\n }\n\n /// @dev `supportsInterface` is the one name in this base that cannot carry the `Skinny` prefix —\n /// ERC-165 fixes its selector — so it is the single point a consumer holding a fat tree *and* a\n /// skinny one has to reconcile, where every other name in the two families is disjoint by\n /// construction. Both families root at OpenZeppelin's `ERC165`, so that reconciliation is the\n /// usual one-liner and the `super` walk covers both:\n ///\n /// function supportsInterface(\n /// bytes4 interfaceId\n /// ) public view override(FatIMTReadableStorage, SkinnyIMTReadableStorage) returns (bool) {\n /// return super.supportsInterface(interfaceId);\n /// }\n ///\n /// A consumer of one family inherits the right answer and writes nothing at all.\n function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {\n return interfaceId == type(ISkinnyIMTReadableEvent).interfaceId || super.supportsInterface(interfaceId);\n }\n\n function getSkinnySideNodes(\n uint256 treeId,\n uint256 firstIndex,\n uint256 endIndex\n ) external view virtual override returns (uint256[] memory) {\n return InternalSkinnyIMTEvent._getSideNodes(_initializedSkinnyEventTree(treeId), firstIndex, endIndex);\n }\n\n function getSkinnyRoot(uint256 treeId) external view virtual override returns (uint256) {\n return InternalSkinnyIMTEvent._root(_initializedSkinnyEventTree(treeId));\n }\n\n function getSkinnySize(uint256 treeId) external view virtual override returns (uint256) {\n return _initializedSkinnyEventTree(treeId).size;\n }\n\n function getSkinnyDepth(uint256 treeId) external view virtual override returns (uint256) {\n return _initializedSkinnyEventTree(treeId).depth;\n }\n}\n"
243
+ },
244
+ "npm/@warptoad/skinny-imt.sol@0.0.11/SkinnyIMTReadableStorage.sol": {
245
+ "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.20;\n\nimport {SkinnyIMTDataStorage, InternalSkinnyIMTStorage} from \"./InternalSkinnyIMTStorage.sol\";\nimport {SkinnyIMTDataEvent} from \"./InternalSkinnyIMTEvent.sol\";\nimport {NotInitialized} from \"./InternalSkinnyIMTEvent.sol\";\nimport {SkinnyIMTReadableEvent} from \"./SkinnyIMTReadableEvent.sol\";\nimport {IERC165} from \"@openzeppelin/contracts/utils/introspection/IERC165.sol\";\nimport {ISkinnyIMTReadableStorage} from \"./interfaces/ISkinnyIMTReadableStorage.sol\";\n\n/// @title SkinnyIMTReadableStorage\n/// @dev inheritable interface so any contract with a skinny tree has a common interface for clients side libs to read\n///\n/// Same shape as `SkinnyIMTReadableEvent`, plus the two readers that only the storage variant can\n/// serve: `getSkinnyLeaves` off its `leaves` array, and `getSkinnyLeavesBaseSlot` for clients that\n/// read that array straight out of storage.\nabstract contract SkinnyIMTReadableStorage is SkinnyIMTReadableEvent, ISkinnyIMTReadableStorage {\n /// @dev Resolves `treeId` to the consumer's tree storage. Single-tree consumers may ignore `treeId`.\n function _getSkinnyStorageTree(uint256 treeId) internal view virtual returns (SkinnyIMTDataStorage storage);\n\n /// @dev Override this if you have both a storage and a event tree\n function _getSkinnyEventTree(uint256 treeId) internal view virtual override returns (SkinnyIMTDataEvent storage) {\n return _getSkinnyStorageTree(treeId).treeData;\n }\n\n function _initializedSkinnyStorageTree(uint256 treeId) internal view returns (SkinnyIMTDataStorage storage) {\n SkinnyIMTDataStorage storage tree = _getSkinnyStorageTree(treeId);\n if (tree.treeData.treeId == 0) {\n revert NotInitialized();\n }\n return tree;\n }\n\n /// @dev Only the id this base adds; `super` walks on to `SkinnyIMTReadableEvent` for the event id\n /// and OpenZeppelin's `ERC165` for `0x01ffc9a7`. Note this id covers *only* `getSkinnyLeaves` and\n /// `getSkinnyLeavesBaseSlot` — inherited functions are excluded from `type(I).interfaceId` — so a\n /// client after the whole read ABI checks the event id too.\n function supportsInterface(\n bytes4 interfaceId\n ) public view virtual override(SkinnyIMTReadableEvent, IERC165) returns (bool) {\n return interfaceId == type(ISkinnyIMTReadableStorage).interfaceId || super.supportsInterface(interfaceId);\n }\n\n function getSkinnyLeaves(\n uint256 treeId,\n uint256 firstIndex,\n uint256 endIndex\n ) external view virtual override returns (uint256[] memory) {\n return InternalSkinnyIMTStorage._getLeaves(_initializedSkinnyStorageTree(treeId), firstIndex, endIndex);\n }\n\n function getSkinnyLeavesBaseSlot(uint256 treeId) external view virtual override returns (uint256) {\n SkinnyIMTDataStorage storage tree = _initializedSkinnyStorageTree(treeId);\n uint256 slot;\n assembly {\n slot := tree.slot\n }\n return slot;\n }\n}\n"
246
+ },
247
+ "npm/@warptoad/skinny-imt.sol@0.0.11/SkinnyIMTUtils.sol": {
248
+ "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.4;\n\nimport {IIMTEvents} from \"./interfaces/IIMTEvents.sol\";\nimport {SNARK_SCALAR_FIELD} from \"./Constants.sol\";\nimport {SkinnyIMTData} from \"./InternalSkinnyIMTCore.sol\";\n\nerror LeafGreaterThanSnarkScalarField();\n\n// // @TODO ask zemse if the wants to make Poseidon2Yul_BN254 an library with public functions, would add 50~150 gas\n// // Hardcoded since poseidon2 is deployed as a contract instead of a library\n// // This is because author used a gas saving trick with .fallback\n// // address internal constant HASHER_ADDRESS = 0xB2542195Ad96AcfBC962C48A97D7640A9F5386D2;\n// // The function used for hashing. Passed as a function parameter in functions from InternalLazyIMT.\n// // function hasher(uint256[2] memory leaves) internal pure returns (uint256) {\n// // return IPoseidon2(HASHER_ADDRESS).hash_2(leaves[0], leaves[1]);\n// // }\n\n// // The function used for hashing. Passed as a function parameter in functions from InternalLazyIMT.\n// function _poseidon2Hasher(uint256[2] memory leaves) pure returns (uint256) {\n// return LibPoseidon2Yul.hash_2(leaves[0], leaves[1]);\n// }\n\n/// @dev Emits one `UpdatedLeaf` per updated leaf, mirroring `update`.\nfunction _emitUpdatedMany(\n uint256 treeId,\n uint256[] calldata leafIndexes,\n uint256[] calldata oldLeaves,\n uint256[] calldata newLeaves\n) {\n for (uint256 i = 0; i < leafIndexes.length; i++) {\n emit IIMTEvents.UpdatedLeaf(treeId, leafIndexes[i], newLeaves[i], oldLeaves[i]);\n }\n}\n\n/// @dev Reverts with `LeafGreaterThanSnarkScalarField` if `v` is not in the BN254 scalar field.\nfunction _requireInField(uint256 v) pure {\n if (v >= SNARK_SCALAR_FIELD) {\n revert LeafGreaterThanSnarkScalarField();\n }\n}\n\n/// @dev Reverts unless every value is within the snark scalar field.\nfunction _requireAllInField(uint256[] calldata values) pure {\n for (uint256 i = 0; i < values.length; i++) {\n _requireInField(values[i]);\n }\n}\n"
249
+ },
250
+ "npm/poseidon2-evm@2.0.0/src/bn254/yul/LibPoseidon2Yul.sol": {
251
+ "content": "// SPDX-License-Identifier: MIT\n// This file is generated by generate-yul.ts. Do not edit manually.\n\npragma solidity >=0.6.0;\n\n/// @notice Poseidon2 hash function library optimized in Yul assembly\n/// @dev Internal functions can be inlined without deploying a contract\n/// Security: https://github.com/zemse/poseidon2-evm/blob/main/SECURITY.md\nlibrary LibPoseidon2Yul {\n function hash_1(uint256 x) internal pure returns (uint256) {\n return poseidon2_core(x, 0, 0, 1 << 64);\n }\n\n function hash_2(uint256 x, uint256 y) internal pure returns (uint256) {\n return poseidon2_core(x, y, 0, 2 << 64);\n }\n\n function hash_3(uint256 x, uint256 y, uint256 z) internal pure returns (uint256) {\n return poseidon2_core(x, y, z, 3 << 64);\n }\n\n function poseidon2_core(uint256 s0, uint256 s1, uint256 s2, uint256 s3) internal pure returns (uint256 result) {\n assembly {\n let PRIME := 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001\n\n let state0 := mod(s0, PRIME)\n let state1 := mod(s1, PRIME)\n let state2 := mod(s2, PRIME)\n let state3 := mod(s3, PRIME)\n\n // Apply 1st linear layer\n\n {\n // matrix_multiplication_4x4\n let t0 := add(state0, state1) // dirty 2/3\n let t1 := add(state2, state3) // dirty 2/3\n let t2 := add(state1, state1)\n t2 := addmod(t2, t1, PRIME) // clean\n let t3 := add(state3, state3)\n t3 := addmod(t3, t0, PRIME) // clean\n let t4 := mulmod(t1, 4, PRIME)\n t4 := add(t4, t3) // dirty 1/3\n let t5 := mulmod(t0, 4, PRIME)\n t5 := add(t5, t2) // dirty 1/3\n let t6 := addmod(t3, t5, PRIME) // clean\n let t7 := addmod(t2, t4, PRIME) // clean\n state0 := t6 // clean\n state1 := t5 // dirty 1/3\n state2 := t7 // clean\n state3 := t4 // dirty 1/3\n }\n\n // External rounds (first half)\n\n // Round 0 (external)\n {\n state0 := add(state0, 0x19b849f69450b06848da1d39bd5e4a4302bb86744edc26238b0878e269ed23e5)\n state1 := add(state1, 0x265ddfe127dd51bd7239347b758f0a1320eb2cc7450acc1dad47f80c8dcf34d6)\n state2 := add(state2, 0x199750ec472f1809e0f66a545e1e51624108ac845015c2aa3dfc36bab497d8aa)\n state3 := add(state3, 0x157ff3fe65ac7208110f06a5f74302b14d743ea25067f0ffd032f787c7f1cdf8)\n\n // full s_box\n\n {\n // single_box\n let intr := state0\n state0 := mulmod(intr, intr, PRIME)\n state0 := mulmod(state0, state0, PRIME)\n state0 := mulmod(state0, intr, PRIME)\n }\n\n {\n // single_box\n let intr := state1\n state1 := mulmod(intr, intr, PRIME)\n state1 := mulmod(state1, state1, PRIME)\n state1 := mulmod(state1, intr, PRIME)\n }\n\n {\n // single_box\n let intr := state2\n state2 := mulmod(intr, intr, PRIME)\n state2 := mulmod(state2, state2, PRIME)\n state2 := mulmod(state2, intr, PRIME)\n }\n\n {\n // single_box\n let intr := state3\n state3 := mulmod(intr, intr, PRIME)\n state3 := mulmod(state3, state3, PRIME)\n state3 := mulmod(state3, intr, PRIME)\n }\n\n {\n // matrix_multiplication_4x4\n let t0 := add(state0, state1) // dirty 2/3\n let t1 := add(state2, state3) // dirty 2/3\n let t2 := add(state1, state1)\n t2 := addmod(t2, t1, PRIME) // clean\n let t3 := add(state3, state3)\n t3 := addmod(t3, t0, PRIME) // clean\n let t4 := mulmod(t1, 4, PRIME)\n t4 := add(t4, t3) // dirty 1/3\n let t5 := mulmod(t0, 4, PRIME)\n t5 := add(t5, t2) // dirty 1/3\n let t6 := addmod(t3, t5, PRIME) // clean\n let t7 := addmod(t2, t4, PRIME) // clean\n state0 := t6 // clean\n state1 := t5 // dirty 1/3\n state2 := t7 // clean\n state3 := t4 // dirty 1/3\n }\n }\n\n // Round 1 (external)\n {\n state0 := add(state0, 0x2e49c43c4569dd9c5fd35ac45fca33f10b15c590692f8beefe18f4896ac94902)\n state1 := add(state1, 0x0e35fb89981890520d4aef2b6d6506c3cb2f0b6973c24fa82731345ffa2d1f1e)\n state2 := add(state2, 0x251ad47cb15c4f1105f109ae5e944f1ba9d9e7806d667ffec6fe723002e0b996)\n state3 := add(state3, 0x13da07dc64d428369873e97160234641f8beb56fdd05e5f3563fa39d9c22df4e)\n\n // full s_box\n\n {\n // single_box\n let intr := state0\n state0 := mulmod(intr, intr, PRIME)\n state0 := mulmod(state0, state0, PRIME)\n state0 := mulmod(state0, intr, PRIME)\n }\n\n {\n // single_box\n let intr := state1\n state1 := mulmod(intr, intr, PRIME)\n state1 := mulmod(state1, state1, PRIME)\n state1 := mulmod(state1, intr, PRIME)\n }\n\n {\n // single_box\n let intr := state2\n state2 := mulmod(intr, intr, PRIME)\n state2 := mulmod(state2, state2, PRIME)\n state2 := mulmod(state2, intr, PRIME)\n }\n\n {\n // single_box\n let intr := state3\n state3 := mulmod(intr, intr, PRIME)\n state3 := mulmod(state3, state3, PRIME)\n state3 := mulmod(state3, intr, PRIME)\n }\n\n {\n // matrix_multiplication_4x4\n let t0 := add(state0, state1) // dirty 2/3\n let t1 := add(state2, state3) // dirty 2/3\n let t2 := add(state1, state1)\n t2 := addmod(t2, t1, PRIME) // clean\n let t3 := add(state3, state3)\n t3 := addmod(t3, t0, PRIME) // clean\n let t4 := mulmod(t1, 4, PRIME)\n t4 := add(t4, t3) // dirty 1/3\n let t5 := mulmod(t0, 4, PRIME)\n t5 := add(t5, t2) // dirty 1/3\n let t6 := addmod(t3, t5, PRIME) // clean\n let t7 := addmod(t2, t4, PRIME) // clean\n state0 := t6 // clean\n state1 := t5 // dirty 1/3\n state2 := t7 // clean\n state3 := t4 // dirty 1/3\n }\n }\n\n // Round 2 (external)\n {\n state0 := add(state0, 0x0c009b84e650e6d23dc00c7dccef7483a553939689d350cd46e7b89055fd4738)\n state1 := add(state1, 0x011f16b1c63a854f01992e3956f42d8b04eb650c6d535eb0203dec74befdca06)\n state2 := add(state2, 0x0ed69e5e383a688f209d9a561daa79612f3f78d0467ad45485df07093f367549)\n state3 := add(state3, 0x04dba94a7b0ce9e221acad41472b6bbe3aec507f5eb3d33f463672264c9f789b)\n\n // full s_box\n\n {\n // single_box\n let intr := state0\n state0 := mulmod(intr, intr, PRIME)\n state0 := mulmod(state0, state0, PRIME)\n state0 := mulmod(state0, intr, PRIME)\n }\n\n {\n // single_box\n let intr := state1\n state1 := mulmod(intr, intr, PRIME)\n state1 := mulmod(state1, state1, PRIME)\n state1 := mulmod(state1, intr, PRIME)\n }\n\n {\n // single_box\n let intr := state2\n state2 := mulmod(intr, intr, PRIME)\n state2 := mulmod(state2, state2, PRIME)\n state2 := mulmod(state2, intr, PRIME)\n }\n\n {\n // single_box\n let intr := state3\n state3 := mulmod(intr, intr, PRIME)\n state3 := mulmod(state3, state3, PRIME)\n state3 := mulmod(state3, intr, PRIME)\n }\n\n {\n // matrix_multiplication_4x4\n let t0 := add(state0, state1) // dirty 2/3\n let t1 := add(state2, state3) // dirty 2/3\n let t2 := add(state1, state1)\n t2 := addmod(t2, t1, PRIME) // clean\n let t3 := add(state3, state3)\n t3 := addmod(t3, t0, PRIME) // clean\n let t4 := mulmod(t1, 4, PRIME)\n t4 := add(t4, t3) // dirty 1/3\n let t5 := mulmod(t0, 4, PRIME)\n t5 := add(t5, t2) // dirty 1/3\n let t6 := addmod(t3, t5, PRIME) // clean\n let t7 := addmod(t2, t4, PRIME) // clean\n state0 := t6 // clean\n state1 := t5 // dirty 1/3\n state2 := t7 // clean\n state3 := t4 // dirty 1/3\n }\n }\n\n // Round 3 (external)\n {\n state0 := add(state0, 0x0a3f2637d840f3a16eb094271c9d237b6036757d4bb50bf7ce732ff1d4fa28e8)\n state1 := add(state1, 0x259a666f129eea198f8a1c502fdb38fa39b1f075569564b6e54a485d1182323f)\n state2 := add(state2, 0x28bf7459c9b2f4c6d8e7d06a4ee3a47f7745d4271038e5157a32fdf7ede0d6a1)\n state3 := add(state3, 0x0a1ca941f057037526ea200f489be8d4c37c85bbcce6a2aeec91bd6941432447)\n\n // full s_box\n\n {\n // single_box\n let intr := state0\n state0 := mulmod(intr, intr, PRIME)\n state0 := mulmod(state0, state0, PRIME)\n state0 := mulmod(state0, intr, PRIME)\n }\n\n {\n // single_box\n let intr := state1\n state1 := mulmod(intr, intr, PRIME)\n state1 := mulmod(state1, state1, PRIME)\n state1 := mulmod(state1, intr, PRIME)\n }\n\n {\n // single_box\n let intr := state2\n state2 := mulmod(intr, intr, PRIME)\n state2 := mulmod(state2, state2, PRIME)\n state2 := mulmod(state2, intr, PRIME)\n }\n\n {\n // single_box\n let intr := state3\n state3 := mulmod(intr, intr, PRIME)\n state3 := mulmod(state3, state3, PRIME)\n state3 := mulmod(state3, intr, PRIME)\n }\n\n {\n // matrix_multiplication_4x4\n let t0 := add(state0, state1) // dirty 2/3\n let t1 := add(state2, state3) // dirty 2/3\n let t2 := add(state1, state1)\n t2 := addmod(t2, t1, PRIME) // clean\n let t3 := add(state3, state3)\n t3 := addmod(t3, t0, PRIME) // clean\n let t4 := mulmod(t1, 4, PRIME)\n t4 := addmod(t4, t3, PRIME) // clean\n let t5 := mulmod(t0, 4, PRIME)\n t5 := addmod(t5, t2, PRIME) // clean\n let t6 := addmod(t3, t5, PRIME) // clean\n let t7 := addmod(t2, t4, PRIME) // clean\n state0 := t6 // clean\n state1 := t5 // clean\n state2 := t7 // clean\n state3 := t4 // clean\n }\n }\n\n // Internal rounds\n\n // Round 4 (internal)\n {\n state0 := add(state0, 0x0c6f8f958be0e93053d7fd4fc54512855535ed1539f051dcb43a26fd926361cf)\n\n {\n // single_box\n let intr := state0\n state0 := mulmod(intr, intr, PRIME)\n state0 := mulmod(state0, state0, PRIME)\n state0 := mulmod(state0, intr, PRIME)\n }\n\n {\n // internal_m_multiplication\n let sum := add(state0, state1)\n sum := add(sum, state2)\n sum := addmod(sum, state3, PRIME)\n state0 := addmod(\n mulmod(state0, 0x10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e7, PRIME),\n sum,\n PRIME\n )\n state1 := addmod(\n mulmod(state1, 0x0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b, PRIME),\n sum,\n PRIME\n )\n state2 := addmod(\n mulmod(state2, 0x00544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac15, PRIME),\n sum,\n PRIME\n )\n state3 := addmod(\n mulmod(state3, 0x222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b, PRIME),\n sum,\n PRIME\n )\n }\n }\n\n // Round 5 (internal)\n {\n state0 := add(state0, 0x123106a93cd17578d426e8128ac9d90aa9e8a00708e296e084dd57e69caaf811)\n\n {\n // single_box\n let intr := state0\n state0 := mulmod(intr, intr, PRIME)\n state0 := mulmod(state0, state0, PRIME)\n state0 := mulmod(state0, intr, PRIME)\n }\n\n {\n // internal_m_multiplication\n let sum := add(state0, state1)\n sum := add(sum, state2)\n sum := addmod(sum, state3, PRIME)\n state0 := addmod(\n mulmod(state0, 0x10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e7, PRIME),\n sum,\n PRIME\n )\n state1 := addmod(\n mulmod(state1, 0x0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b, PRIME),\n sum,\n PRIME\n )\n state2 := addmod(\n mulmod(state2, 0x00544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac15, PRIME),\n sum,\n PRIME\n )\n state3 := addmod(\n mulmod(state3, 0x222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b, PRIME),\n sum,\n PRIME\n )\n }\n }\n\n // Round 6 (internal)\n {\n state0 := add(state0, 0x26e1ba52ad9285d97dd3ab52f8e840085e8fa83ff1e8f1877b074867cd2dee75)\n\n {\n // single_box\n let intr := state0\n state0 := mulmod(intr, intr, PRIME)\n state0 := mulmod(state0, state0, PRIME)\n state0 := mulmod(state0, intr, PRIME)\n }\n\n {\n // internal_m_multiplication\n let sum := add(state0, state1)\n sum := add(sum, state2)\n sum := addmod(sum, state3, PRIME)\n state0 := addmod(\n mulmod(state0, 0x10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e7, PRIME),\n sum,\n PRIME\n )\n state1 := addmod(\n mulmod(state1, 0x0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b, PRIME),\n sum,\n PRIME\n )\n state2 := addmod(\n mulmod(state2, 0x00544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac15, PRIME),\n sum,\n PRIME\n )\n state3 := addmod(\n mulmod(state3, 0x222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b, PRIME),\n sum,\n PRIME\n )\n }\n }\n\n // Round 7 (internal)\n {\n state0 := add(state0, 0x1cb55cad7bd133de18a64c5c47b9c97cbe4d8b7bf9e095864471537e6a4ae2c5)\n\n {\n // single_box\n let intr := state0\n state0 := mulmod(intr, intr, PRIME)\n state0 := mulmod(state0, state0, PRIME)\n state0 := mulmod(state0, intr, PRIME)\n }\n\n {\n // internal_m_multiplication\n let sum := add(state0, state1)\n sum := add(sum, state2)\n sum := addmod(sum, state3, PRIME)\n state0 := addmod(\n mulmod(state0, 0x10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e7, PRIME),\n sum,\n PRIME\n )\n state1 := addmod(\n mulmod(state1, 0x0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b, PRIME),\n sum,\n PRIME\n )\n state2 := addmod(\n mulmod(state2, 0x00544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac15, PRIME),\n sum,\n PRIME\n )\n state3 := addmod(\n mulmod(state3, 0x222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b, PRIME),\n sum,\n PRIME\n )\n }\n }\n\n // Round 8 (internal)\n {\n state0 := add(state0, 0x1dcd73e46acd8f8e0e2c7ce04bde7f6d2a53043d5060a41c7143f08e6e9055d0)\n\n {\n // single_box\n let intr := state0\n state0 := mulmod(intr, intr, PRIME)\n state0 := mulmod(state0, state0, PRIME)\n state0 := mulmod(state0, intr, PRIME)\n }\n\n {\n // internal_m_multiplication\n let sum := add(state0, state1)\n sum := add(sum, state2)\n sum := addmod(sum, state3, PRIME)\n state0 := addmod(\n mulmod(state0, 0x10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e7, PRIME),\n sum,\n PRIME\n )\n state1 := addmod(\n mulmod(state1, 0x0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b, PRIME),\n sum,\n PRIME\n )\n state2 := addmod(\n mulmod(state2, 0x00544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac15, PRIME),\n sum,\n PRIME\n )\n state3 := addmod(\n mulmod(state3, 0x222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b, PRIME),\n sum,\n PRIME\n )\n }\n }\n\n // Round 9 (internal)\n {\n state0 := add(state0, 0x011003e32f6d9c66f5852f05474a4def0cda294a0eb4e9b9b12b9bb4512e5574)\n\n {\n // single_box\n let intr := state0\n state0 := mulmod(intr, intr, PRIME)\n state0 := mulmod(state0, state0, PRIME)\n state0 := mulmod(state0, intr, PRIME)\n }\n\n {\n // internal_m_multiplication\n let sum := add(state0, state1)\n sum := add(sum, state2)\n sum := addmod(sum, state3, PRIME)\n state0 := addmod(\n mulmod(state0, 0x10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e7, PRIME),\n sum,\n PRIME\n )\n state1 := addmod(\n mulmod(state1, 0x0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b, PRIME),\n sum,\n PRIME\n )\n state2 := addmod(\n mulmod(state2, 0x00544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac15, PRIME),\n sum,\n PRIME\n )\n state3 := addmod(\n mulmod(state3, 0x222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b, PRIME),\n sum,\n PRIME\n )\n }\n }\n\n // Round 10 (internal)\n {\n state0 := add(state0, 0x2b1e809ac1d10ab29ad5f20d03a57dfebadfe5903f58bafed7c508dd2287ae8c)\n\n {\n // single_box\n let intr := state0\n state0 := mulmod(intr, intr, PRIME)\n state0 := mulmod(state0, state0, PRIME)\n state0 := mulmod(state0, intr, PRIME)\n }\n\n {\n // internal_m_multiplication\n let sum := add(state0, state1)\n sum := add(sum, state2)\n sum := addmod(sum, state3, PRIME)\n state0 := addmod(\n mulmod(state0, 0x10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e7, PRIME),\n sum,\n PRIME\n )\n state1 := addmod(\n mulmod(state1, 0x0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b, PRIME),\n sum,\n PRIME\n )\n state2 := addmod(\n mulmod(state2, 0x00544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac15, PRIME),\n sum,\n PRIME\n )\n state3 := addmod(\n mulmod(state3, 0x222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b, PRIME),\n sum,\n PRIME\n )\n }\n }\n\n // Round 11 (internal)\n {\n state0 := add(state0, 0x2539de1785b735999fb4dac35ee17ed0ef995d05ab2fc5faeaa69ae87bcec0a5)\n\n {\n // single_box\n let intr := state0\n state0 := mulmod(intr, intr, PRIME)\n state0 := mulmod(state0, state0, PRIME)\n state0 := mulmod(state0, intr, PRIME)\n }\n\n {\n // internal_m_multiplication\n let sum := add(state0, state1)\n sum := add(sum, state2)\n sum := addmod(sum, state3, PRIME)\n state0 := addmod(\n mulmod(state0, 0x10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e7, PRIME),\n sum,\n PRIME\n )\n state1 := addmod(\n mulmod(state1, 0x0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b, PRIME),\n sum,\n PRIME\n )\n state2 := addmod(\n mulmod(state2, 0x00544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac15, PRIME),\n sum,\n PRIME\n )\n state3 := addmod(\n mulmod(state3, 0x222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b, PRIME),\n sum,\n PRIME\n )\n }\n }\n\n // Round 12 (internal)\n {\n state0 := add(state0, 0x0c246c5a2ef8ee0126497f222b3e0a0ef4e1c3d41c86d46e43982cb11d77951d)\n\n {\n // single_box\n let intr := state0\n state0 := mulmod(intr, intr, PRIME)\n state0 := mulmod(state0, state0, PRIME)\n state0 := mulmod(state0, intr, PRIME)\n }\n\n {\n // internal_m_multiplication\n let sum := add(state0, state1)\n sum := add(sum, state2)\n sum := addmod(sum, state3, PRIME)\n state0 := addmod(\n mulmod(state0, 0x10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e7, PRIME),\n sum,\n PRIME\n )\n state1 := addmod(\n mulmod(state1, 0x0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b, PRIME),\n sum,\n PRIME\n )\n state2 := addmod(\n mulmod(state2, 0x00544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac15, PRIME),\n sum,\n PRIME\n )\n state3 := addmod(\n mulmod(state3, 0x222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b, PRIME),\n sum,\n PRIME\n )\n }\n }\n\n // Round 13 (internal)\n {\n state0 := add(state0, 0x192089c4974f68e95408148f7c0632edbb09e6a6ad1a1c2f3f0305f5d03b527b)\n\n {\n // single_box\n let intr := state0\n state0 := mulmod(intr, intr, PRIME)\n state0 := mulmod(state0, state0, PRIME)\n state0 := mulmod(state0, intr, PRIME)\n }\n\n {\n // internal_m_multiplication\n let sum := add(state0, state1)\n sum := add(sum, state2)\n sum := addmod(sum, state3, PRIME)\n state0 := addmod(\n mulmod(state0, 0x10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e7, PRIME),\n sum,\n PRIME\n )\n state1 := addmod(\n mulmod(state1, 0x0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b, PRIME),\n sum,\n PRIME\n )\n state2 := addmod(\n mulmod(state2, 0x00544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac15, PRIME),\n sum,\n PRIME\n )\n state3 := addmod(\n mulmod(state3, 0x222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b, PRIME),\n sum,\n PRIME\n )\n }\n }\n\n // Round 14 (internal)\n {\n state0 := add(state0, 0x1eae0ad8ab68b2f06a0ee36eeb0d0c058529097d91096b756d8fdc2fb5a60d85)\n\n {\n // single_box\n let intr := state0\n state0 := mulmod(intr, intr, PRIME)\n state0 := mulmod(state0, state0, PRIME)\n state0 := mulmod(state0, intr, PRIME)\n }\n\n {\n // internal_m_multiplication\n let sum := add(state0, state1)\n sum := add(sum, state2)\n sum := addmod(sum, state3, PRIME)\n state0 := addmod(\n mulmod(state0, 0x10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e7, PRIME),\n sum,\n PRIME\n )\n state1 := addmod(\n mulmod(state1, 0x0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b, PRIME),\n sum,\n PRIME\n )\n state2 := addmod(\n mulmod(state2, 0x00544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac15, PRIME),\n sum,\n PRIME\n )\n state3 := addmod(\n mulmod(state3, 0x222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b, PRIME),\n sum,\n PRIME\n )\n }\n }\n\n // Round 15 (internal)\n {\n state0 := add(state0, 0x179190e5d0e22179e46f8282872abc88db6e2fdc0dee99e69768bd98c5d06bfb)\n\n {\n // single_box\n let intr := state0\n state0 := mulmod(intr, intr, PRIME)\n state0 := mulmod(state0, state0, PRIME)\n state0 := mulmod(state0, intr, PRIME)\n }\n\n {\n // internal_m_multiplication\n let sum := add(state0, state1)\n sum := add(sum, state2)\n sum := addmod(sum, state3, PRIME)\n state0 := addmod(\n mulmod(state0, 0x10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e7, PRIME),\n sum,\n PRIME\n )\n state1 := addmod(\n mulmod(state1, 0x0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b, PRIME),\n sum,\n PRIME\n )\n state2 := addmod(\n mulmod(state2, 0x00544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac15, PRIME),\n sum,\n PRIME\n )\n state3 := addmod(\n mulmod(state3, 0x222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b, PRIME),\n sum,\n PRIME\n )\n }\n }\n\n // Round 16 (internal)\n {\n state0 := add(state0, 0x29bb9e2c9076732576e9a81c7ac4b83214528f7db00f31bf6cafe794a9b3cd1c)\n\n {\n // single_box\n let intr := state0\n state0 := mulmod(intr, intr, PRIME)\n state0 := mulmod(state0, state0, PRIME)\n state0 := mulmod(state0, intr, PRIME)\n }\n\n {\n // internal_m_multiplication\n let sum := add(state0, state1)\n sum := add(sum, state2)\n sum := addmod(sum, state3, PRIME)\n state0 := addmod(\n mulmod(state0, 0x10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e7, PRIME),\n sum,\n PRIME\n )\n state1 := addmod(\n mulmod(state1, 0x0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b, PRIME),\n sum,\n PRIME\n )\n state2 := addmod(\n mulmod(state2, 0x00544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac15, PRIME),\n sum,\n PRIME\n )\n state3 := addmod(\n mulmod(state3, 0x222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b, PRIME),\n sum,\n PRIME\n )\n }\n }\n\n // Round 17 (internal)\n {\n state0 := add(state0, 0x225d394e42207599403efd0c2464a90d52652645882aac35b10e590e6e691e08)\n\n {\n // single_box\n let intr := state0\n state0 := mulmod(intr, intr, PRIME)\n state0 := mulmod(state0, state0, PRIME)\n state0 := mulmod(state0, intr, PRIME)\n }\n\n {\n // internal_m_multiplication\n let sum := add(state0, state1)\n sum := add(sum, state2)\n sum := addmod(sum, state3, PRIME)\n state0 := addmod(\n mulmod(state0, 0x10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e7, PRIME),\n sum,\n PRIME\n )\n state1 := addmod(\n mulmod(state1, 0x0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b, PRIME),\n sum,\n PRIME\n )\n state2 := addmod(\n mulmod(state2, 0x00544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac15, PRIME),\n sum,\n PRIME\n )\n state3 := addmod(\n mulmod(state3, 0x222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b, PRIME),\n sum,\n PRIME\n )\n }\n }\n\n // Round 18 (internal)\n {\n state0 := add(state0, 0x064760623c25c8cf753d238055b444532be13557451c087de09efd454b23fd59)\n\n {\n // single_box\n let intr := state0\n state0 := mulmod(intr, intr, PRIME)\n state0 := mulmod(state0, state0, PRIME)\n state0 := mulmod(state0, intr, PRIME)\n }\n\n {\n // internal_m_multiplication\n let sum := add(state0, state1)\n sum := add(sum, state2)\n sum := addmod(sum, state3, PRIME)\n state0 := addmod(\n mulmod(state0, 0x10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e7, PRIME),\n sum,\n PRIME\n )\n state1 := addmod(\n mulmod(state1, 0x0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b, PRIME),\n sum,\n PRIME\n )\n state2 := addmod(\n mulmod(state2, 0x00544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac15, PRIME),\n sum,\n PRIME\n )\n state3 := addmod(\n mulmod(state3, 0x222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b, PRIME),\n sum,\n PRIME\n )\n }\n }\n\n // Round 19 (internal)\n {\n state0 := add(state0, 0x10ba3a0e01df92e87f301c4b716d8a394d67f4bf42a75c10922910a78f6b5b87)\n\n {\n // single_box\n let intr := state0\n state0 := mulmod(intr, intr, PRIME)\n state0 := mulmod(state0, state0, PRIME)\n state0 := mulmod(state0, intr, PRIME)\n }\n\n {\n // internal_m_multiplication\n let sum := add(state0, state1)\n sum := add(sum, state2)\n sum := addmod(sum, state3, PRIME)\n state0 := addmod(\n mulmod(state0, 0x10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e7, PRIME),\n sum,\n PRIME\n )\n state1 := addmod(\n mulmod(state1, 0x0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b, PRIME),\n sum,\n PRIME\n )\n state2 := addmod(\n mulmod(state2, 0x00544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac15, PRIME),\n sum,\n PRIME\n )\n state3 := addmod(\n mulmod(state3, 0x222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b, PRIME),\n sum,\n PRIME\n )\n }\n }\n\n // Round 20 (internal)\n {\n state0 := add(state0, 0x0e070bf53f8451b24f9c6e96b0c2a801cb511bc0c242eb9d361b77693f21471c)\n\n {\n // single_box\n let intr := state0\n state0 := mulmod(intr, intr, PRIME)\n state0 := mulmod(state0, state0, PRIME)\n state0 := mulmod(state0, intr, PRIME)\n }\n\n {\n // internal_m_multiplication\n let sum := add(state0, state1)\n sum := add(sum, state2)\n sum := addmod(sum, state3, PRIME)\n state0 := addmod(\n mulmod(state0, 0x10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e7, PRIME),\n sum,\n PRIME\n )\n state1 := addmod(\n mulmod(state1, 0x0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b, PRIME),\n sum,\n PRIME\n )\n state2 := addmod(\n mulmod(state2, 0x00544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac15, PRIME),\n sum,\n PRIME\n )\n state3 := addmod(\n mulmod(state3, 0x222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b, PRIME),\n sum,\n PRIME\n )\n }\n }\n\n // Round 21 (internal)\n {\n state0 := add(state0, 0x1b94cd61b051b04dd39755ff93821a73ccd6cb11d2491d8aa7f921014de252fb)\n\n {\n // single_box\n let intr := state0\n state0 := mulmod(intr, intr, PRIME)\n state0 := mulmod(state0, state0, PRIME)\n state0 := mulmod(state0, intr, PRIME)\n }\n\n {\n // internal_m_multiplication\n let sum := add(state0, state1)\n sum := add(sum, state2)\n sum := addmod(sum, state3, PRIME)\n state0 := addmod(\n mulmod(state0, 0x10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e7, PRIME),\n sum,\n PRIME\n )\n state1 := addmod(\n mulmod(state1, 0x0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b, PRIME),\n sum,\n PRIME\n )\n state2 := addmod(\n mulmod(state2, 0x00544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac15, PRIME),\n sum,\n PRIME\n )\n state3 := addmod(\n mulmod(state3, 0x222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b, PRIME),\n sum,\n PRIME\n )\n }\n }\n\n // Round 22 (internal)\n {\n state0 := add(state0, 0x1d7cb39bafb8c744e148787a2e70230f9d4e917d5713bb050487b5aa7d74070b)\n\n {\n // single_box\n let intr := state0\n state0 := mulmod(intr, intr, PRIME)\n state0 := mulmod(state0, state0, PRIME)\n state0 := mulmod(state0, intr, PRIME)\n }\n\n {\n // internal_m_multiplication\n let sum := add(state0, state1)\n sum := add(sum, state2)\n sum := addmod(sum, state3, PRIME)\n state0 := addmod(\n mulmod(state0, 0x10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e7, PRIME),\n sum,\n PRIME\n )\n state1 := addmod(\n mulmod(state1, 0x0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b, PRIME),\n sum,\n PRIME\n )\n state2 := addmod(\n mulmod(state2, 0x00544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac15, PRIME),\n sum,\n PRIME\n )\n state3 := addmod(\n mulmod(state3, 0x222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b, PRIME),\n sum,\n PRIME\n )\n }\n }\n\n // Round 23 (internal)\n {\n state0 := add(state0, 0x2ec93189bd1ab4f69117d0fe980c80ff8785c2961829f701bb74ac1f303b17db)\n\n {\n // single_box\n let intr := state0\n state0 := mulmod(intr, intr, PRIME)\n state0 := mulmod(state0, state0, PRIME)\n state0 := mulmod(state0, intr, PRIME)\n }\n\n {\n // internal_m_multiplication\n let sum := add(state0, state1)\n sum := add(sum, state2)\n sum := addmod(sum, state3, PRIME)\n state0 := addmod(\n mulmod(state0, 0x10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e7, PRIME),\n sum,\n PRIME\n )\n state1 := addmod(\n mulmod(state1, 0x0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b, PRIME),\n sum,\n PRIME\n )\n state2 := addmod(\n mulmod(state2, 0x00544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac15, PRIME),\n sum,\n PRIME\n )\n state3 := addmod(\n mulmod(state3, 0x222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b, PRIME),\n sum,\n PRIME\n )\n }\n }\n\n // Round 24 (internal)\n {\n state0 := add(state0, 0x2db366bfdd36d277a692bb825b86275beac404a19ae07a9082ea46bd83517926)\n\n {\n // single_box\n let intr := state0\n state0 := mulmod(intr, intr, PRIME)\n state0 := mulmod(state0, state0, PRIME)\n state0 := mulmod(state0, intr, PRIME)\n }\n\n {\n // internal_m_multiplication\n let sum := add(state0, state1)\n sum := add(sum, state2)\n sum := addmod(sum, state3, PRIME)\n state0 := addmod(\n mulmod(state0, 0x10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e7, PRIME),\n sum,\n PRIME\n )\n state1 := addmod(\n mulmod(state1, 0x0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b, PRIME),\n sum,\n PRIME\n )\n state2 := addmod(\n mulmod(state2, 0x00544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac15, PRIME),\n sum,\n PRIME\n )\n state3 := addmod(\n mulmod(state3, 0x222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b, PRIME),\n sum,\n PRIME\n )\n }\n }\n\n // Round 25 (internal)\n {\n state0 := add(state0, 0x062100eb485db06269655cf186a68532985275428450359adc99cec6960711b8)\n\n {\n // single_box\n let intr := state0\n state0 := mulmod(intr, intr, PRIME)\n state0 := mulmod(state0, state0, PRIME)\n state0 := mulmod(state0, intr, PRIME)\n }\n\n {\n // internal_m_multiplication\n let sum := add(state0, state1)\n sum := add(sum, state2)\n sum := addmod(sum, state3, PRIME)\n state0 := addmod(\n mulmod(state0, 0x10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e7, PRIME),\n sum,\n PRIME\n )\n state1 := addmod(\n mulmod(state1, 0x0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b, PRIME),\n sum,\n PRIME\n )\n state2 := addmod(\n mulmod(state2, 0x00544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac15, PRIME),\n sum,\n PRIME\n )\n state3 := addmod(\n mulmod(state3, 0x222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b, PRIME),\n sum,\n PRIME\n )\n }\n }\n\n // Round 26 (internal)\n {\n state0 := add(state0, 0x0761d33c66614aaa570e7f1e8244ca1120243f92fa59e4f900c567bf41f5a59b)\n\n {\n // single_box\n let intr := state0\n state0 := mulmod(intr, intr, PRIME)\n state0 := mulmod(state0, state0, PRIME)\n state0 := mulmod(state0, intr, PRIME)\n }\n\n {\n // internal_m_multiplication\n let sum := add(state0, state1)\n sum := add(sum, state2)\n sum := addmod(sum, state3, PRIME)\n state0 := addmod(\n mulmod(state0, 0x10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e7, PRIME),\n sum,\n PRIME\n )\n state1 := addmod(\n mulmod(state1, 0x0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b, PRIME),\n sum,\n PRIME\n )\n state2 := addmod(\n mulmod(state2, 0x00544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac15, PRIME),\n sum,\n PRIME\n )\n state3 := addmod(\n mulmod(state3, 0x222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b, PRIME),\n sum,\n PRIME\n )\n }\n }\n\n // Round 27 (internal)\n {\n state0 := add(state0, 0x20fc411a114d13992c2705aa034e3f315d78608a0f7de4ccf7a72e494855ad0d)\n\n {\n // single_box\n let intr := state0\n state0 := mulmod(intr, intr, PRIME)\n state0 := mulmod(state0, state0, PRIME)\n state0 := mulmod(state0, intr, PRIME)\n }\n\n {\n // internal_m_multiplication\n let sum := add(state0, state1)\n sum := add(sum, state2)\n sum := addmod(sum, state3, PRIME)\n state0 := addmod(\n mulmod(state0, 0x10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e7, PRIME),\n sum,\n PRIME\n )\n state1 := addmod(\n mulmod(state1, 0x0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b, PRIME),\n sum,\n PRIME\n )\n state2 := addmod(\n mulmod(state2, 0x00544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac15, PRIME),\n sum,\n PRIME\n )\n state3 := addmod(\n mulmod(state3, 0x222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b, PRIME),\n sum,\n PRIME\n )\n }\n }\n\n // Round 28 (internal)\n {\n state0 := add(state0, 0x25b5c004a4bdfcb5add9ec4e9ab219ba102c67e8b3effb5fc3a30f317250bc5a)\n\n {\n // single_box\n let intr := state0\n state0 := mulmod(intr, intr, PRIME)\n state0 := mulmod(state0, state0, PRIME)\n state0 := mulmod(state0, intr, PRIME)\n }\n\n {\n // internal_m_multiplication\n let sum := add(state0, state1)\n sum := add(sum, state2)\n sum := addmod(sum, state3, PRIME)\n state0 := addmod(\n mulmod(state0, 0x10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e7, PRIME),\n sum,\n PRIME\n )\n state1 := addmod(\n mulmod(state1, 0x0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b, PRIME),\n sum,\n PRIME\n )\n state2 := addmod(\n mulmod(state2, 0x00544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac15, PRIME),\n sum,\n PRIME\n )\n state3 := addmod(\n mulmod(state3, 0x222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b, PRIME),\n sum,\n PRIME\n )\n }\n }\n\n // Round 29 (internal)\n {\n state0 := add(state0, 0x23b1822d278ed632a494e58f6df6f5ed038b186d8474155ad87e7dff62b37f4b)\n\n {\n // single_box\n let intr := state0\n state0 := mulmod(intr, intr, PRIME)\n state0 := mulmod(state0, state0, PRIME)\n state0 := mulmod(state0, intr, PRIME)\n }\n\n {\n // internal_m_multiplication\n let sum := add(state0, state1)\n sum := add(sum, state2)\n sum := addmod(sum, state3, PRIME)\n state0 := addmod(\n mulmod(state0, 0x10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e7, PRIME),\n sum,\n PRIME\n )\n state1 := addmod(\n mulmod(state1, 0x0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b, PRIME),\n sum,\n PRIME\n )\n state2 := addmod(\n mulmod(state2, 0x00544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac15, PRIME),\n sum,\n PRIME\n )\n state3 := addmod(\n mulmod(state3, 0x222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b, PRIME),\n sum,\n PRIME\n )\n }\n }\n\n // Round 30 (internal)\n {\n state0 := add(state0, 0x22734b4c5c3f9493606c4ba9012499bf0f14d13bfcfcccaa16102a29cc2f69e0)\n\n {\n // single_box\n let intr := state0\n state0 := mulmod(intr, intr, PRIME)\n state0 := mulmod(state0, state0, PRIME)\n state0 := mulmod(state0, intr, PRIME)\n }\n\n {\n // internal_m_multiplication\n let sum := add(state0, state1)\n sum := add(sum, state2)\n sum := addmod(sum, state3, PRIME)\n state0 := addmod(\n mulmod(state0, 0x10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e7, PRIME),\n sum,\n PRIME\n )\n state1 := addmod(\n mulmod(state1, 0x0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b, PRIME),\n sum,\n PRIME\n )\n state2 := addmod(\n mulmod(state2, 0x00544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac15, PRIME),\n sum,\n PRIME\n )\n state3 := addmod(\n mulmod(state3, 0x222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b, PRIME),\n sum,\n PRIME\n )\n }\n }\n\n // Round 31 (internal)\n {\n state0 := add(state0, 0x26c0c8fe09eb30b7e27a74dc33492347e5bdff409aa3610254413d3fad795ce5)\n\n {\n // single_box\n let intr := state0\n state0 := mulmod(intr, intr, PRIME)\n state0 := mulmod(state0, state0, PRIME)\n state0 := mulmod(state0, intr, PRIME)\n }\n\n {\n // internal_m_multiplication\n let sum := add(state0, state1)\n sum := add(sum, state2)\n sum := addmod(sum, state3, PRIME)\n state0 := addmod(\n mulmod(state0, 0x10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e7, PRIME),\n sum,\n PRIME\n )\n state1 := addmod(\n mulmod(state1, 0x0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b, PRIME),\n sum,\n PRIME\n )\n state2 := addmod(\n mulmod(state2, 0x00544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac15, PRIME),\n sum,\n PRIME\n )\n state3 := addmod(\n mulmod(state3, 0x222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b, PRIME),\n sum,\n PRIME\n )\n }\n }\n\n // Round 32 (internal)\n {\n state0 := add(state0, 0x070dd0ccb6bd7bbae88eac03fa1fbb26196be3083a809829bbd626df348ccad9)\n\n {\n // single_box\n let intr := state0\n state0 := mulmod(intr, intr, PRIME)\n state0 := mulmod(state0, state0, PRIME)\n state0 := mulmod(state0, intr, PRIME)\n }\n\n {\n // internal_m_multiplication\n let sum := add(state0, state1)\n sum := add(sum, state2)\n sum := addmod(sum, state3, PRIME)\n state0 := addmod(\n mulmod(state0, 0x10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e7, PRIME),\n sum,\n PRIME\n )\n state1 := addmod(\n mulmod(state1, 0x0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b, PRIME),\n sum,\n PRIME\n )\n state2 := addmod(\n mulmod(state2, 0x00544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac15, PRIME),\n sum,\n PRIME\n )\n state3 := addmod(\n mulmod(state3, 0x222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b, PRIME),\n sum,\n PRIME\n )\n }\n }\n\n // Round 33 (internal)\n {\n state0 := add(state0, 0x12b6595bdb329b6fb043ba78bb28c3bec2c0a6de46d8c5ad6067c4ebfd4250da)\n\n {\n // single_box\n let intr := state0\n state0 := mulmod(intr, intr, PRIME)\n state0 := mulmod(state0, state0, PRIME)\n state0 := mulmod(state0, intr, PRIME)\n }\n\n {\n // internal_m_multiplication\n let sum := add(state0, state1)\n sum := add(sum, state2)\n sum := addmod(sum, state3, PRIME)\n state0 := addmod(\n mulmod(state0, 0x10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e7, PRIME),\n sum,\n PRIME\n )\n state1 := addmod(\n mulmod(state1, 0x0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b, PRIME),\n sum,\n PRIME\n )\n state2 := addmod(\n mulmod(state2, 0x00544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac15, PRIME),\n sum,\n PRIME\n )\n state3 := addmod(\n mulmod(state3, 0x222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b, PRIME),\n sum,\n PRIME\n )\n }\n }\n\n // Round 34 (internal)\n {\n state0 := add(state0, 0x248d97d7f76283d63bec30e7a5876c11c06fca9b275c671c5e33d95bb7e8d729)\n\n {\n // single_box\n let intr := state0\n state0 := mulmod(intr, intr, PRIME)\n state0 := mulmod(state0, state0, PRIME)\n state0 := mulmod(state0, intr, PRIME)\n }\n\n {\n // internal_m_multiplication\n let sum := add(state0, state1)\n sum := add(sum, state2)\n sum := addmod(sum, state3, PRIME)\n state0 := addmod(\n mulmod(state0, 0x10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e7, PRIME),\n sum,\n PRIME\n )\n state1 := addmod(\n mulmod(state1, 0x0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b, PRIME),\n sum,\n PRIME\n )\n state2 := addmod(\n mulmod(state2, 0x00544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac15, PRIME),\n sum,\n PRIME\n )\n state3 := addmod(\n mulmod(state3, 0x222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b, PRIME),\n sum,\n PRIME\n )\n }\n }\n\n // Round 35 (internal)\n {\n state0 := add(state0, 0x1a306d439d463b0816fc6fd64cc939318b45eb759ddde4aa106d15d9bd9baaaa)\n\n {\n // single_box\n let intr := state0\n state0 := mulmod(intr, intr, PRIME)\n state0 := mulmod(state0, state0, PRIME)\n state0 := mulmod(state0, intr, PRIME)\n }\n\n {\n // internal_m_multiplication\n let sum := add(state0, state1)\n sum := add(sum, state2)\n sum := addmod(sum, state3, PRIME)\n state0 := addmod(\n mulmod(state0, 0x10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e7, PRIME),\n sum,\n PRIME\n )\n state1 := addmod(\n mulmod(state1, 0x0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b, PRIME),\n sum,\n PRIME\n )\n state2 := addmod(\n mulmod(state2, 0x00544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac15, PRIME),\n sum,\n PRIME\n )\n state3 := addmod(\n mulmod(state3, 0x222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b, PRIME),\n sum,\n PRIME\n )\n }\n }\n\n // Round 36 (internal)\n {\n state0 := add(state0, 0x28a8f8372e3c38daced7c00421cb4621f4f1b54ddc27821b0d62d3d6ec7c56cf)\n\n {\n // single_box\n let intr := state0\n state0 := mulmod(intr, intr, PRIME)\n state0 := mulmod(state0, state0, PRIME)\n state0 := mulmod(state0, intr, PRIME)\n }\n\n {\n // internal_m_multiplication\n let sum := add(state0, state1)\n sum := add(sum, state2)\n sum := addmod(sum, state3, PRIME)\n state0 := addmod(\n mulmod(state0, 0x10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e7, PRIME),\n sum,\n PRIME\n )\n state1 := addmod(\n mulmod(state1, 0x0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b, PRIME),\n sum,\n PRIME\n )\n state2 := addmod(\n mulmod(state2, 0x00544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac15, PRIME),\n sum,\n PRIME\n )\n state3 := addmod(\n mulmod(state3, 0x222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b, PRIME),\n sum,\n PRIME\n )\n }\n }\n\n // Round 37 (internal)\n {\n state0 := add(state0, 0x0094975717f9a8a8bb35152f24d43294071ce320c829f388bc852183e1e2ce7e)\n\n {\n // single_box\n let intr := state0\n state0 := mulmod(intr, intr, PRIME)\n state0 := mulmod(state0, state0, PRIME)\n state0 := mulmod(state0, intr, PRIME)\n }\n\n {\n // internal_m_multiplication\n let sum := add(state0, state1)\n sum := add(sum, state2)\n sum := addmod(sum, state3, PRIME)\n state0 := addmod(\n mulmod(state0, 0x10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e7, PRIME),\n sum,\n PRIME\n )\n state1 := addmod(\n mulmod(state1, 0x0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b, PRIME),\n sum,\n PRIME\n )\n state2 := addmod(\n mulmod(state2, 0x00544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac15, PRIME),\n sum,\n PRIME\n )\n state3 := addmod(\n mulmod(state3, 0x222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b, PRIME),\n sum,\n PRIME\n )\n }\n }\n\n // Round 38 (internal)\n {\n state0 := add(state0, 0x04d5ee4c3aa78f7d80fde60d716480d3593f74d4f653ae83f4103246db2e8d65)\n\n {\n // single_box\n let intr := state0\n state0 := mulmod(intr, intr, PRIME)\n state0 := mulmod(state0, state0, PRIME)\n state0 := mulmod(state0, intr, PRIME)\n }\n\n {\n // internal_m_multiplication\n let sum := add(state0, state1)\n sum := add(sum, state2)\n sum := addmod(sum, state3, PRIME)\n state0 := addmod(\n mulmod(state0, 0x10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e7, PRIME),\n sum,\n PRIME\n )\n state1 := addmod(\n mulmod(state1, 0x0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b, PRIME),\n sum,\n PRIME\n )\n state2 := addmod(\n mulmod(state2, 0x00544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac15, PRIME),\n sum,\n PRIME\n )\n state3 := addmod(\n mulmod(state3, 0x222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b, PRIME),\n sum,\n PRIME\n )\n }\n }\n\n // Round 39 (internal)\n {\n state0 := add(state0, 0x2a6cf5e9aa03d4336349ad6fb8ed2269c7bef54b8822cc76d08495c12efde187)\n\n {\n // single_box\n let intr := state0\n state0 := mulmod(intr, intr, PRIME)\n state0 := mulmod(state0, state0, PRIME)\n state0 := mulmod(state0, intr, PRIME)\n }\n\n {\n // internal_m_multiplication\n let sum := add(state0, state1)\n sum := add(sum, state2)\n sum := addmod(sum, state3, PRIME)\n state0 := addmod(\n mulmod(state0, 0x10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e7, PRIME),\n sum,\n PRIME\n )\n state1 := addmod(\n mulmod(state1, 0x0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b, PRIME),\n sum,\n PRIME\n )\n state2 := addmod(\n mulmod(state2, 0x00544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac15, PRIME),\n sum,\n PRIME\n )\n state3 := addmod(\n mulmod(state3, 0x222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b, PRIME),\n sum,\n PRIME\n )\n }\n }\n\n // Round 40 (internal)\n {\n state0 := add(state0, 0x2304d31eaab960ba9274da43e19ddeb7f792180808fd6e43baae48d7efcba3f3)\n\n {\n // single_box\n let intr := state0\n state0 := mulmod(intr, intr, PRIME)\n state0 := mulmod(state0, state0, PRIME)\n state0 := mulmod(state0, intr, PRIME)\n }\n\n {\n // internal_m_multiplication\n let sum := add(state0, state1)\n sum := add(sum, state2)\n sum := addmod(sum, state3, PRIME)\n state0 := addmod(\n mulmod(state0, 0x10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e7, PRIME),\n sum,\n PRIME\n )\n state1 := addmod(\n mulmod(state1, 0x0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b, PRIME),\n sum,\n PRIME\n )\n state2 := addmod(\n mulmod(state2, 0x00544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac15, PRIME),\n sum,\n PRIME\n )\n state3 := addmod(\n mulmod(state3, 0x222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b, PRIME),\n sum,\n PRIME\n )\n }\n }\n\n // Round 41 (internal)\n {\n state0 := add(state0, 0x03fd9ac865a4b2a6d5e7009785817249bff08a7e0726fcb4e1c11d39d199f0b0)\n\n {\n // single_box\n let intr := state0\n state0 := mulmod(intr, intr, PRIME)\n state0 := mulmod(state0, state0, PRIME)\n state0 := mulmod(state0, intr, PRIME)\n }\n\n {\n // internal_m_multiplication\n let sum := add(state0, state1)\n sum := add(sum, state2)\n sum := addmod(sum, state3, PRIME)\n state0 := addmod(\n mulmod(state0, 0x10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e7, PRIME),\n sum,\n PRIME\n )\n state1 := addmod(\n mulmod(state1, 0x0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b, PRIME),\n sum,\n PRIME\n )\n state2 := addmod(\n mulmod(state2, 0x00544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac15, PRIME),\n sum,\n PRIME\n )\n state3 := addmod(\n mulmod(state3, 0x222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b, PRIME),\n sum,\n PRIME\n )\n }\n }\n\n // Round 42 (internal)\n {\n state0 := add(state0, 0x00b7258ded52bbda2248404d55ee5044798afc3a209193073f7954d4d63b0b64)\n\n {\n // single_box\n let intr := state0\n state0 := mulmod(intr, intr, PRIME)\n state0 := mulmod(state0, state0, PRIME)\n state0 := mulmod(state0, intr, PRIME)\n }\n\n {\n // internal_m_multiplication\n let sum := add(state0, state1)\n sum := add(sum, state2)\n sum := addmod(sum, state3, PRIME)\n state0 := addmod(\n mulmod(state0, 0x10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e7, PRIME),\n sum,\n PRIME\n )\n state1 := addmod(\n mulmod(state1, 0x0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b, PRIME),\n sum,\n PRIME\n )\n state2 := addmod(\n mulmod(state2, 0x00544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac15, PRIME),\n sum,\n PRIME\n )\n state3 := addmod(\n mulmod(state3, 0x222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b, PRIME),\n sum,\n PRIME\n )\n }\n }\n\n // Round 43 (internal)\n {\n state0 := add(state0, 0x159f81ada0771799ec38fca2d4bf65ebb13d3a74f3298db36272c5ca65e92d9a)\n\n {\n // single_box\n let intr := state0\n state0 := mulmod(intr, intr, PRIME)\n state0 := mulmod(state0, state0, PRIME)\n state0 := mulmod(state0, intr, PRIME)\n }\n\n {\n // internal_m_multiplication\n let sum := add(state0, state1)\n sum := add(sum, state2)\n sum := addmod(sum, state3, PRIME)\n state0 := addmod(\n mulmod(state0, 0x10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e7, PRIME),\n sum,\n PRIME\n )\n state1 := addmod(\n mulmod(state1, 0x0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b, PRIME),\n sum,\n PRIME\n )\n state2 := addmod(\n mulmod(state2, 0x00544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac15, PRIME),\n sum,\n PRIME\n )\n state3 := addmod(\n mulmod(state3, 0x222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b, PRIME),\n sum,\n PRIME\n )\n }\n }\n\n // Round 44 (internal)\n {\n state0 := add(state0, 0x1ef90e67437fbc8550237a75bc28e3bb9000130ea25f0c5471e144cf4264431f)\n\n {\n // single_box\n let intr := state0\n state0 := mulmod(intr, intr, PRIME)\n state0 := mulmod(state0, state0, PRIME)\n state0 := mulmod(state0, intr, PRIME)\n }\n\n {\n // internal_m_multiplication\n let sum := add(state0, state1)\n sum := add(sum, state2)\n sum := addmod(sum, state3, PRIME)\n state0 := addmod(\n mulmod(state0, 0x10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e7, PRIME),\n sum,\n PRIME\n )\n state1 := addmod(\n mulmod(state1, 0x0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b, PRIME),\n sum,\n PRIME\n )\n state2 := addmod(\n mulmod(state2, 0x00544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac15, PRIME),\n sum,\n PRIME\n )\n state3 := addmod(\n mulmod(state3, 0x222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b, PRIME),\n sum,\n PRIME\n )\n }\n }\n\n // Round 45 (internal)\n {\n state0 := add(state0, 0x1e65f838515e5ff0196b49aa41a2d2568df739bc176b08ec95a79ed82932e30d)\n\n {\n // single_box\n let intr := state0\n state0 := mulmod(intr, intr, PRIME)\n state0 := mulmod(state0, state0, PRIME)\n state0 := mulmod(state0, intr, PRIME)\n }\n\n {\n // internal_m_multiplication\n let sum := add(state0, state1)\n sum := add(sum, state2)\n sum := addmod(sum, state3, PRIME)\n state0 := addmod(\n mulmod(state0, 0x10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e7, PRIME),\n sum,\n PRIME\n )\n state1 := addmod(\n mulmod(state1, 0x0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b, PRIME),\n sum,\n PRIME\n )\n state2 := addmod(\n mulmod(state2, 0x00544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac15, PRIME),\n sum,\n PRIME\n )\n state3 := addmod(\n mulmod(state3, 0x222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b, PRIME),\n sum,\n PRIME\n )\n }\n }\n\n // Round 46 (internal)\n {\n state0 := add(state0, 0x2b1b045def3a166cec6ce768d079ba74b18c844e570e1f826575c1068c94c33f)\n\n {\n // single_box\n let intr := state0\n state0 := mulmod(intr, intr, PRIME)\n state0 := mulmod(state0, state0, PRIME)\n state0 := mulmod(state0, intr, PRIME)\n }\n\n {\n // internal_m_multiplication\n let sum := add(state0, state1)\n sum := add(sum, state2)\n sum := addmod(sum, state3, PRIME)\n state0 := addmod(\n mulmod(state0, 0x10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e7, PRIME),\n sum,\n PRIME\n )\n state1 := addmod(\n mulmod(state1, 0x0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b, PRIME),\n sum,\n PRIME\n )\n state2 := addmod(\n mulmod(state2, 0x00544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac15, PRIME),\n sum,\n PRIME\n )\n state3 := addmod(\n mulmod(state3, 0x222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b, PRIME),\n sum,\n PRIME\n )\n }\n }\n\n // Round 47 (internal)\n {\n state0 := add(state0, 0x0832e5753ceb0ff6402543b1109229c165dc2d73bef715e3f1c6e07c168bb173)\n\n {\n // single_box\n let intr := state0\n state0 := mulmod(intr, intr, PRIME)\n state0 := mulmod(state0, state0, PRIME)\n state0 := mulmod(state0, intr, PRIME)\n }\n\n {\n // internal_m_multiplication\n let sum := add(state0, state1)\n sum := add(sum, state2)\n sum := addmod(sum, state3, PRIME)\n state0 := addmod(\n mulmod(state0, 0x10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e7, PRIME),\n sum,\n PRIME\n )\n state1 := addmod(\n mulmod(state1, 0x0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b, PRIME),\n sum,\n PRIME\n )\n state2 := addmod(\n mulmod(state2, 0x00544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac15, PRIME),\n sum,\n PRIME\n )\n state3 := addmod(\n mulmod(state3, 0x222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b, PRIME),\n sum,\n PRIME\n )\n }\n }\n\n // Round 48 (internal)\n {\n state0 := add(state0, 0x02f614e9cedfb3dc6b762ae0a37d41bab1b841c2e8b6451bc5a8e3c390b6ad16)\n\n {\n // single_box\n let intr := state0\n state0 := mulmod(intr, intr, PRIME)\n state0 := mulmod(state0, state0, PRIME)\n state0 := mulmod(state0, intr, PRIME)\n }\n\n {\n // internal_m_multiplication\n let sum := add(state0, state1)\n sum := add(sum, state2)\n sum := addmod(sum, state3, PRIME)\n state0 := addmod(\n mulmod(state0, 0x10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e7, PRIME),\n sum,\n PRIME\n )\n state1 := addmod(\n mulmod(state1, 0x0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b, PRIME),\n sum,\n PRIME\n )\n state2 := addmod(\n mulmod(state2, 0x00544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac15, PRIME),\n sum,\n PRIME\n )\n state3 := addmod(\n mulmod(state3, 0x222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b, PRIME),\n sum,\n PRIME\n )\n }\n }\n\n // Round 49 (internal)\n {\n state0 := add(state0, 0x0e2427d38bd46a60dd640b8e362cad967370ebb777bedff40f6a0be27e7ed705)\n\n {\n // single_box\n let intr := state0\n state0 := mulmod(intr, intr, PRIME)\n state0 := mulmod(state0, state0, PRIME)\n state0 := mulmod(state0, intr, PRIME)\n }\n\n {\n // internal_m_multiplication\n let sum := add(state0, state1)\n sum := add(sum, state2)\n sum := addmod(sum, state3, PRIME)\n state0 := addmod(\n mulmod(state0, 0x10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e7, PRIME),\n sum,\n PRIME\n )\n state1 := addmod(\n mulmod(state1, 0x0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b, PRIME),\n sum,\n PRIME\n )\n state2 := addmod(\n mulmod(state2, 0x00544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac15, PRIME),\n sum,\n PRIME\n )\n state3 := addmod(\n mulmod(state3, 0x222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b, PRIME),\n sum,\n PRIME\n )\n }\n }\n\n // Round 50 (internal)\n {\n state0 := add(state0, 0x0493630b7c670b6deb7c84d414e7ce79049f0ec098c3c7c50768bbe29214a53a)\n\n {\n // single_box\n let intr := state0\n state0 := mulmod(intr, intr, PRIME)\n state0 := mulmod(state0, state0, PRIME)\n state0 := mulmod(state0, intr, PRIME)\n }\n\n {\n // internal_m_multiplication\n let sum := add(state0, state1)\n sum := add(sum, state2)\n sum := addmod(sum, state3, PRIME)\n state0 := addmod(\n mulmod(state0, 0x10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e7, PRIME),\n sum,\n PRIME\n )\n state1 := addmod(\n mulmod(state1, 0x0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b, PRIME),\n sum,\n PRIME\n )\n state2 := addmod(\n mulmod(state2, 0x00544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac15, PRIME),\n sum,\n PRIME\n )\n state3 := addmod(\n mulmod(state3, 0x222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b, PRIME),\n sum,\n PRIME\n )\n }\n }\n\n // Round 51 (internal)\n {\n state0 := add(state0, 0x22ead100e8e482674decdab17066c5a26bb1515355d5461a3dc06cc85327cea9)\n\n {\n // single_box\n let intr := state0\n state0 := mulmod(intr, intr, PRIME)\n state0 := mulmod(state0, state0, PRIME)\n state0 := mulmod(state0, intr, PRIME)\n }\n\n {\n // internal_m_multiplication\n let sum := add(state0, state1)\n sum := add(sum, state2)\n sum := addmod(sum, state3, PRIME)\n state0 := addmod(\n mulmod(state0, 0x10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e7, PRIME),\n sum,\n PRIME\n )\n state1 := addmod(\n mulmod(state1, 0x0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b, PRIME),\n sum,\n PRIME\n )\n state2 := addmod(\n mulmod(state2, 0x00544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac15, PRIME),\n sum,\n PRIME\n )\n state3 := addmod(\n mulmod(state3, 0x222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b, PRIME),\n sum,\n PRIME\n )\n }\n }\n\n // Round 52 (internal)\n {\n state0 := add(state0, 0x25b3e56e655b42cdaae2626ed2554d48583f1ae35626d04de5084e0b6d2a6f16)\n\n {\n // single_box\n let intr := state0\n state0 := mulmod(intr, intr, PRIME)\n state0 := mulmod(state0, state0, PRIME)\n state0 := mulmod(state0, intr, PRIME)\n }\n\n {\n // internal_m_multiplication\n let sum := add(state0, state1)\n sum := add(sum, state2)\n sum := addmod(sum, state3, PRIME)\n state0 := addmod(\n mulmod(state0, 0x10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e7, PRIME),\n sum,\n PRIME\n )\n state1 := addmod(\n mulmod(state1, 0x0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b, PRIME),\n sum,\n PRIME\n )\n state2 := addmod(\n mulmod(state2, 0x00544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac15, PRIME),\n sum,\n PRIME\n )\n state3 := addmod(\n mulmod(state3, 0x222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b, PRIME),\n sum,\n PRIME\n )\n }\n }\n\n // Round 53 (internal)\n {\n state0 := add(state0, 0x1e32752ada8836ef5837a6cde8ff13dbb599c336349e4c584b4fdc0a0cf6f9d0)\n\n {\n // single_box\n let intr := state0\n state0 := mulmod(intr, intr, PRIME)\n state0 := mulmod(state0, state0, PRIME)\n state0 := mulmod(state0, intr, PRIME)\n }\n\n {\n // internal_m_multiplication\n let sum := add(state0, state1)\n sum := add(sum, state2)\n sum := addmod(sum, state3, PRIME)\n state0 := addmod(\n mulmod(state0, 0x10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e7, PRIME),\n sum,\n PRIME\n )\n state1 := addmod(\n mulmod(state1, 0x0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b, PRIME),\n sum,\n PRIME\n )\n state2 := addmod(\n mulmod(state2, 0x00544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac15, PRIME),\n sum,\n PRIME\n )\n state3 := addmod(\n mulmod(state3, 0x222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b, PRIME),\n sum,\n PRIME\n )\n }\n }\n\n // Round 54 (internal)\n {\n state0 := add(state0, 0x2fa2a871c15a387cc50f68f6f3c3455b23c00995f05078f672a9864074d412e5)\n\n {\n // single_box\n let intr := state0\n state0 := mulmod(intr, intr, PRIME)\n state0 := mulmod(state0, state0, PRIME)\n state0 := mulmod(state0, intr, PRIME)\n }\n\n {\n // internal_m_multiplication\n let sum := add(state0, state1)\n sum := add(sum, state2)\n sum := addmod(sum, state3, PRIME)\n state0 := addmod(\n mulmod(state0, 0x10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e7, PRIME),\n sum,\n PRIME\n )\n state1 := addmod(\n mulmod(state1, 0x0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b, PRIME),\n sum,\n PRIME\n )\n state2 := addmod(\n mulmod(state2, 0x00544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac15, PRIME),\n sum,\n PRIME\n )\n state3 := addmod(\n mulmod(state3, 0x222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b, PRIME),\n sum,\n PRIME\n )\n }\n }\n\n // Round 55 (internal)\n {\n state0 := add(state0, 0x2f569b8a9a4424c9278e1db7311e889f54ccbf10661bab7fcd18e7c7a7d83505)\n\n {\n // single_box\n let intr := state0\n state0 := mulmod(intr, intr, PRIME)\n state0 := mulmod(state0, state0, PRIME)\n state0 := mulmod(state0, intr, PRIME)\n }\n\n {\n // internal_m_multiplication\n let sum := add(state0, state1)\n sum := add(sum, state2)\n sum := addmod(sum, state3, PRIME)\n state0 := addmod(\n mulmod(state0, 0x10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e7, PRIME),\n sum,\n PRIME\n )\n state1 := addmod(\n mulmod(state1, 0x0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b, PRIME),\n sum,\n PRIME\n )\n state2 := addmod(\n mulmod(state2, 0x00544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac15, PRIME),\n sum,\n PRIME\n )\n state3 := addmod(\n mulmod(state3, 0x222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b, PRIME),\n sum,\n PRIME\n )\n }\n }\n\n // Round 56 (internal)\n {\n state0 := add(state0, 0x044cb455110a8fdd531ade530234c518a7df93f7332ffd2144165374b246b43d)\n\n {\n // single_box\n let intr := state0\n state0 := mulmod(intr, intr, PRIME)\n state0 := mulmod(state0, state0, PRIME)\n state0 := mulmod(state0, intr, PRIME)\n }\n\n {\n // internal_m_multiplication\n let sum := add(state0, state1)\n sum := add(sum, state2)\n sum := addmod(sum, state3, PRIME)\n state0 := addmod(\n mulmod(state0, 0x10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e7, PRIME),\n sum,\n PRIME\n )\n state1 := addmod(\n mulmod(state1, 0x0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b, PRIME),\n sum,\n PRIME\n )\n state2 := addmod(\n mulmod(state2, 0x00544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac15, PRIME),\n sum,\n PRIME\n )\n state3 := addmod(\n mulmod(state3, 0x222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b, PRIME),\n sum,\n PRIME\n )\n }\n }\n\n // Round 57 (internal)\n {\n state0 := add(state0, 0x227808de93906d5d420246157f2e42b191fe8c90adfe118178ddc723a5319025)\n\n {\n // single_box\n let intr := state0\n state0 := mulmod(intr, intr, PRIME)\n state0 := mulmod(state0, state0, PRIME)\n state0 := mulmod(state0, intr, PRIME)\n }\n\n {\n // internal_m_multiplication\n let sum := add(state0, state1)\n sum := add(sum, state2)\n sum := addmod(sum, state3, PRIME)\n state0 := addmod(\n mulmod(state0, 0x10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e7, PRIME),\n sum,\n PRIME\n )\n state1 := addmod(\n mulmod(state1, 0x0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b, PRIME),\n sum,\n PRIME\n )\n state2 := addmod(\n mulmod(state2, 0x00544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac15, PRIME),\n sum,\n PRIME\n )\n state3 := addmod(\n mulmod(state3, 0x222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b, PRIME),\n sum,\n PRIME\n )\n }\n }\n\n // Round 58 (internal)\n {\n state0 := add(state0, 0x02fcca2934e046bc623adead873579865d03781ae090ad4a8579d2e7a6800355)\n\n {\n // single_box\n let intr := state0\n state0 := mulmod(intr, intr, PRIME)\n state0 := mulmod(state0, state0, PRIME)\n state0 := mulmod(state0, intr, PRIME)\n }\n\n {\n // internal_m_multiplication\n let sum := add(state0, state1)\n sum := add(sum, state2)\n sum := addmod(sum, state3, PRIME)\n state0 := addmod(\n mulmod(state0, 0x10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e7, PRIME),\n sum,\n PRIME\n )\n state1 := addmod(\n mulmod(state1, 0x0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b, PRIME),\n sum,\n PRIME\n )\n state2 := addmod(\n mulmod(state2, 0x00544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac15, PRIME),\n sum,\n PRIME\n )\n state3 := addmod(\n mulmod(state3, 0x222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b, PRIME),\n sum,\n PRIME\n )\n }\n }\n\n // Round 59 (internal)\n {\n state0 := add(state0, 0x0ef915f0ac120b876abccceb344a1d36bad3f3c5ab91a8ddcbec2e060d8befac)\n\n {\n // single_box\n let intr := state0\n state0 := mulmod(intr, intr, PRIME)\n state0 := mulmod(state0, state0, PRIME)\n state0 := mulmod(state0, intr, PRIME)\n }\n\n {\n // internal_m_multiplication\n let sum := add(state0, state1)\n sum := add(sum, state2)\n sum := addmod(sum, state3, PRIME)\n state0 := addmod(\n mulmod(state0, 0x10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e7, PRIME),\n sum,\n PRIME\n )\n state1 := addmod(\n mulmod(state1, 0x0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b, PRIME),\n sum,\n PRIME\n )\n state2 := addmod(\n mulmod(state2, 0x00544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac15, PRIME),\n sum,\n PRIME\n )\n state3 := addmod(\n mulmod(state3, 0x222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b, PRIME),\n sum,\n PRIME\n )\n }\n }\n\n // External rounds (second half)\n\n // Round 60 (external)\n {\n state0 := add(state0, 0x1797130f4b7a3e1777eb757bc6f287f6ab0fb85f6be63b09f3b16ef2b1405d38)\n state1 := add(state1, 0x0a76225dc04170ae3306c85abab59e608c7f497c20156d4d36c668555decc6e5)\n state2 := add(state2, 0x1fffb9ec1992d66ba1e77a7b93209af6f8fa76d48acb664796174b5326a31a5c)\n state3 := add(state3, 0x25721c4fc15a3f2853b57c338fa538d85f8fbba6c6b9c6090611889b797b9c5f)\n\n // full s_box\n\n {\n // single_box\n let intr := state0\n state0 := mulmod(intr, intr, PRIME)\n state0 := mulmod(state0, state0, PRIME)\n state0 := mulmod(state0, intr, PRIME)\n }\n\n {\n // single_box\n let intr := state1\n state1 := mulmod(intr, intr, PRIME)\n state1 := mulmod(state1, state1, PRIME)\n state1 := mulmod(state1, intr, PRIME)\n }\n\n {\n // single_box\n let intr := state2\n state2 := mulmod(intr, intr, PRIME)\n state2 := mulmod(state2, state2, PRIME)\n state2 := mulmod(state2, intr, PRIME)\n }\n\n {\n // single_box\n let intr := state3\n state3 := mulmod(intr, intr, PRIME)\n state3 := mulmod(state3, state3, PRIME)\n state3 := mulmod(state3, intr, PRIME)\n }\n\n {\n // matrix_multiplication_4x4\n let t0 := add(state0, state1) // dirty 2/3\n let t1 := add(state2, state3) // dirty 2/3\n let t2 := add(state1, state1)\n t2 := addmod(t2, t1, PRIME) // clean\n let t3 := add(state3, state3)\n t3 := addmod(t3, t0, PRIME) // clean\n let t4 := mulmod(t1, 4, PRIME)\n t4 := add(t4, t3) // dirty 1/3\n let t5 := mulmod(t0, 4, PRIME)\n t5 := add(t5, t2) // dirty 1/3\n let t6 := addmod(t3, t5, PRIME) // clean\n let t7 := addmod(t2, t4, PRIME) // clean\n state0 := t6 // clean\n state1 := t5 // dirty 1/3\n state2 := t7 // clean\n state3 := t4 // dirty 1/3\n }\n }\n\n // Round 61 (external)\n {\n state0 := add(state0, 0x0c817fd42d5f7a41215e3d07ba197216adb4c3790705da95eb63b982bfcaf75a)\n state1 := add(state1, 0x13abe3f5239915d39f7e13c2c24970b6df8cf86ce00a22002bc15866e52b5a96)\n state2 := add(state2, 0x2106feea546224ea12ef7f39987a46c85c1bc3dc29bdbd7a92cd60acb4d391ce)\n state3 := add(state3, 0x21ca859468a746b6aaa79474a37dab49f1ca5a28c748bc7157e1b3345bb0f959)\n\n // full s_box\n\n {\n // single_box\n let intr := state0\n state0 := mulmod(intr, intr, PRIME)\n state0 := mulmod(state0, state0, PRIME)\n state0 := mulmod(state0, intr, PRIME)\n }\n\n {\n // single_box\n let intr := state1\n state1 := mulmod(intr, intr, PRIME)\n state1 := mulmod(state1, state1, PRIME)\n state1 := mulmod(state1, intr, PRIME)\n }\n\n {\n // single_box\n let intr := state2\n state2 := mulmod(intr, intr, PRIME)\n state2 := mulmod(state2, state2, PRIME)\n state2 := mulmod(state2, intr, PRIME)\n }\n\n {\n // single_box\n let intr := state3\n state3 := mulmod(intr, intr, PRIME)\n state3 := mulmod(state3, state3, PRIME)\n state3 := mulmod(state3, intr, PRIME)\n }\n\n {\n // matrix_multiplication_4x4\n let t0 := add(state0, state1) // dirty 2/3\n let t1 := add(state2, state3) // dirty 2/3\n let t2 := add(state1, state1)\n t2 := addmod(t2, t1, PRIME) // clean\n let t3 := add(state3, state3)\n t3 := addmod(t3, t0, PRIME) // clean\n let t4 := mulmod(t1, 4, PRIME)\n t4 := add(t4, t3) // dirty 1/3\n let t5 := mulmod(t0, 4, PRIME)\n t5 := add(t5, t2) // dirty 1/3\n let t6 := addmod(t3, t5, PRIME) // clean\n let t7 := addmod(t2, t4, PRIME) // clean\n state0 := t6 // clean\n state1 := t5 // dirty 1/3\n state2 := t7 // clean\n state3 := t4 // dirty 1/3\n }\n }\n\n // Round 62 (external)\n {\n state0 := add(state0, 0x05ccd6255c1e6f0c5cf1f0df934194c62911d14d0321662a8f1a48999e34185b)\n state1 := add(state1, 0x0f0e34a64b70a626e464d846674c4c8816c4fb267fe44fe6ea28678cb09490a4)\n state2 := add(state2, 0x0558531a4e25470c6157794ca36d0e9647dbfcfe350d64838f5b1a8a2de0d4bf)\n state3 := add(state3, 0x09d3dca9173ed2faceea125157683d18924cadad3f655a60b72f5864961f1455)\n\n // full s_box\n\n {\n // single_box\n let intr := state0\n state0 := mulmod(intr, intr, PRIME)\n state0 := mulmod(state0, state0, PRIME)\n state0 := mulmod(state0, intr, PRIME)\n }\n\n {\n // single_box\n let intr := state1\n state1 := mulmod(intr, intr, PRIME)\n state1 := mulmod(state1, state1, PRIME)\n state1 := mulmod(state1, intr, PRIME)\n }\n\n {\n // single_box\n let intr := state2\n state2 := mulmod(intr, intr, PRIME)\n state2 := mulmod(state2, state2, PRIME)\n state2 := mulmod(state2, intr, PRIME)\n }\n\n {\n // single_box\n let intr := state3\n state3 := mulmod(intr, intr, PRIME)\n state3 := mulmod(state3, state3, PRIME)\n state3 := mulmod(state3, intr, PRIME)\n }\n\n {\n // matrix_multiplication_4x4\n let t0 := add(state0, state1) // dirty 2/3\n let t1 := add(state2, state3) // dirty 2/3\n let t2 := add(state1, state1)\n t2 := addmod(t2, t1, PRIME) // clean\n let t3 := add(state3, state3)\n t3 := addmod(t3, t0, PRIME) // clean\n let t4 := mulmod(t1, 4, PRIME)\n t4 := add(t4, t3) // dirty 1/3\n let t5 := mulmod(t0, 4, PRIME)\n t5 := add(t5, t2) // dirty 1/3\n let t6 := addmod(t3, t5, PRIME) // clean\n let t7 := addmod(t2, t4, PRIME) // clean\n state0 := t6 // clean\n state1 := t5 // dirty 1/3\n state2 := t7 // clean\n state3 := t4 // dirty 1/3\n }\n }\n\n // Round 63 (external)\n {\n state0 := add(state0, 0x0328cbd54e8c0913493f866ed03d218bf23f92d68aaec48617d4c722e5bd4335)\n state1 := add(state1, 0x2bf07216e2aff0a223a487b1a7094e07e79e7bcc9798c648ee3347dd5329d34b)\n state2 := add(state2, 0x1daf345a58006b736499c583cb76c316d6f78ed6a6dffc82111e11a63fe412df)\n state3 := add(state3, 0x176563472456aaa746b694c60e1823611ef39039b2edc7ff391e6f2293d2c404)\n\n // full s_box\n\n {\n // single_box\n let intr := state0\n state0 := mulmod(intr, intr, PRIME)\n state0 := mulmod(state0, state0, PRIME)\n state0 := mulmod(state0, intr, PRIME)\n }\n\n {\n // single_box\n let intr := state1\n state1 := mulmod(intr, intr, PRIME)\n state1 := mulmod(state1, state1, PRIME)\n state1 := mulmod(state1, intr, PRIME)\n }\n\n {\n // single_box\n let intr := state2\n state2 := mulmod(intr, intr, PRIME)\n state2 := mulmod(state2, state2, PRIME)\n state2 := mulmod(state2, intr, PRIME)\n }\n\n {\n // single_box\n let intr := state3\n state3 := mulmod(intr, intr, PRIME)\n state3 := mulmod(state3, state3, PRIME)\n state3 := mulmod(state3, intr, PRIME)\n }\n\n {\n // matrix_multiplication_4x4\n let t0 := add(state0, state1) // dirty 2/3\n let t1 := add(state2, state3) // dirty 2/3\n let t2 := add(state1, state1)\n t2 := addmod(t2, t1, PRIME) // clean\n let t3 := add(state3, state3)\n t3 := addmod(t3, t0, PRIME) // clean\n let t4 := mulmod(t1, 4, PRIME)\n t4 := add(t4, t3) // dirty 1/3\n let t5 := mulmod(t0, 4, PRIME)\n t5 := add(t5, t2) // dirty 1/3\n let t6 := addmod(t3, t5, PRIME) // clean\n let t7 := addmod(t2, t4, PRIME) // clean\n state0 := t6 // clean\n state1 := t5 // dirty 1/3\n state2 := t7 // clean\n state3 := t4 // dirty 1/3\n }\n }\n\n result := state0\n }\n }\n}\n"
252
+ },
253
+ "project/contracts/SkinnyFat.sol": {
254
+ "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.28;\n\n// TODO FatIMTData exported in FatIMTPoseidon2WriteFullNode?\n// TODO Drop the node it's cleaner\nimport {FatIMTPoseidon2WriteStorage, FatIMTDataStorage} from \"@warptoad/fat-imt.sol/poseidon2/FatIMTPoseidon2WriteStorage.sol\";\n\n// TODO FatIMTData -> FatIMTDataEvent\nimport {FatIMTPoseidon2WriteEvent, FatIMTDataEvent} from \"@warptoad/fat-imt.sol/poseidon2/FatIMTPoseidon2WriteEvent.sol\";\nimport {FatIMTReadableEvent} from \"@warptoad/fat-imt.sol/FatIMTReadableEvent.sol\";\n\nimport {SkinnyIMTPoseidon2WriteStorage, SkinnyIMTDataStorage} from \"@warptoad/skinny-imt.sol/poseidon2/SkinnyIMTPoseidon2WriteStorage.sol\";\n\nimport {SkinnyIMTPoseidon2WriteEvent, SkinnyIMTDataEvent} from \"@warptoad/skinny-imt.sol/poseidon2/SkinnyIMTPoseidon2WriteEvent.sol\";\nimport {SkinnyIMTDataEvent} from \"@warptoad/skinny-imt.sol/InternalSkinnyIMTEvent.sol\";\n\nimport {FatIMTPoseidon2Read} from \"@warptoad/fat-imt.sol/poseidon2/FatIMTPoseidon2Read.sol\";\nimport {SkinnyIMTPoseidon2Read} from \"@warptoad/skinny-imt.sol/poseidon2/SkinnyIMTPoseidon2Read.sol\";\n\nimport {SkinnyIMTReadableStorage} from \"@warptoad/skinny-imt.sol/SkinnyIMTReadableStorage.sol\";\nimport {FatIMTReadableStorage} from \"@warptoad/fat-imt.sol/FatIMTReadableStorage.sol\";\nimport {IIMTEvents} from \"@warptoad/fat-imt.sol/interfaces/IIMTEvents.sol\";\n\nerror WrongTreeId();\nerror TreeHasIncorrectType();\n// TODO nice to have also in the package, but zk-kit structure clashes, so maybe skinny-fat as one package?\nenum TreeType {\n SKINNY_STORAGE,\n SKINNY_EVENT,\n FAT_STORAGE,\n FAT_EVENT\n}\n\ncontract SkinnyFat is\n SkinnyIMTReadableStorage,\n FatIMTReadableStorage,\n IIMTEvents\n{\n //mapping(uint256 => FatIMTDataStorage) fatStorageTrees;\n FatIMTDataStorage[] fatStorageTrees;\n FatIMTDataEvent[] fatEventTrees;\n\n SkinnyIMTDataStorage[] skinnyStorageTrees;\n SkinnyIMTDataEvent[] skinnyEventTrees;\n\n mapping(uint256 => TreeType) treeTypes;\n // you cant really store tree[treeId], since you are now allowed to assign a struct that has a mapping inside of it, to a mapping\n // so we just resolve treeId => index of a array. then just do treeArray[index]. (in one line: `treeArray[indexOfTreeId[treeId]]`)\n mapping(uint256 => uint256) indexOfTreeId;\n\n constructor() {\n FatIMTDataStorage storage fatStorageTree = fatStorageTrees.push();\n uint256 fatStorageTreeId = FatIMTPoseidon2WriteStorage.init(\n fatStorageTree\n );\n treeTypes[fatStorageTreeId] = TreeType.FAT_STORAGE;\n indexOfTreeId[fatStorageTreeId] = fatStorageTrees.length - 1;\n\n FatIMTDataEvent storage fatEventTree = fatEventTrees.push();\n uint256 fatEventTreeId = FatIMTPoseidon2WriteEvent.init(fatEventTree);\n treeTypes[fatEventTreeId] = TreeType.FAT_EVENT;\n indexOfTreeId[fatEventTreeId] = fatEventTrees.length - 1;\n\n SkinnyIMTDataStorage storage skinnyStorageTree = skinnyStorageTrees\n .push();\n uint256 skinnyStorageTreeId = SkinnyIMTPoseidon2WriteStorage.init(\n skinnyStorageTree\n );\n treeTypes[skinnyStorageTreeId] = TreeType.SKINNY_STORAGE;\n indexOfTreeId[skinnyStorageTreeId] = skinnyStorageTrees.length - 1;\n\n SkinnyIMTDataEvent storage skinnyEventTree = skinnyEventTrees.push();\n uint256 skinnyEventTreeId = SkinnyIMTPoseidon2WriteEvent.init(\n skinnyEventTree\n );\n treeTypes[skinnyEventTreeId] = TreeType.SKINNY_EVENT;\n indexOfTreeId[skinnyEventTreeId] = skinnyEventTrees.length - 1;\n }\n\n //\n function supportsInterface(\n bytes4 interfaceId\n )\n public\n view\n override(FatIMTReadableStorage, SkinnyIMTReadableStorage)\n returns (bool)\n {\n // this calls FatIMTReadableStorage.supportsInterface(), which contains a super in it as well which then will\n // call the skinny variant since it is also inherited\n return super.supportsInterface(interfaceId);\n }\n\n // if you'r only using the storage variant, no need to override this SkinnyIMTReadableStorage just passes treeStorage.treeData along\n // if you use both tho do override like this!!\n // if you got more trees. You can store them in a mapping like this\n // TODO this is kinda confusing, the storageReadable inherited contract, re-uses _getSkinnyEventTree by doing .treeData, same needs to happen here\n function _getSkinnyEventTree(\n uint256 treeId\n ) internal view virtual override returns (SkinnyIMTDataEvent storage) {\n uint256 index = indexOfTreeId[treeId];\n if (treeTypes[treeId] == TreeType.SKINNY_STORAGE) {\n return skinnyStorageTrees[index].treeData;\n } else if (treeTypes[treeId] != TreeType.SKINNY_EVENT) {\n revert TreeHasIncorrectType();\n }\n return skinnyEventTrees[index];\n }\n\n // overridable functions so SkinnyIMTFullNodeReadable and SkinnyIMTDataFullNode\n // can find out where the tree is stored so it can expose a interface to get the leaves and storage slot for debug_getStorageRangeAt\n function _getSkinnyStorageTree(\n uint256 treeId\n ) internal view virtual override returns (SkinnyIMTDataStorage storage) {\n uint256 index = indexOfTreeId[treeId];\n if (treeTypes[treeId] != TreeType.SKINNY_STORAGE) {\n revert TreeHasIncorrectType();\n }\n return skinnyStorageTrees[index];\n }\n\n function _getFatEventTree(\n uint256 treeId\n ) internal view virtual override returns (FatIMTDataEvent storage) {\n uint256 index = indexOfTreeId[treeId];\n if (treeTypes[treeId] == TreeType.FAT_STORAGE) {\n return fatStorageTrees[index].treeData;\n } else if (treeTypes[treeId] != TreeType.FAT_EVENT) {\n revert TreeHasIncorrectType();\n }\n return fatEventTrees[index];\n }\n\n // overridable functions so SkinnyIMTFullNodeReadable and SkinnyIMTDataFullNode\n // can find out where the tree is stored so it can expose a interface to get the leaves and storage slot for debug_getStorageRangeAt\n function _getFatStorageTree(\n uint256 treeId\n ) internal view virtual override returns (FatIMTDataStorage storage) {\n uint256 index = indexOfTreeId[treeId];\n if (treeTypes[treeId] != TreeType.FAT_STORAGE) {\n revert TreeHasIncorrectType();\n }\n return fatStorageTrees[index];\n }\n\n function getTreeIds(\n uint256 index\n ) public view returns (uint256, uint256, uint256, uint256) {\n return (\n fatStorageTrees[index].treeData.treeId,\n fatEventTrees[index].treeId,\n skinnyStorageTrees[index].treeData.treeId,\n skinnyEventTrees[index].treeId\n );\n }\n\n function reset() public {\n FatIMTPoseidon2WriteStorage.reset(fatStorageTrees[0]);\n SkinnyIMTPoseidon2WriteStorage.reset(skinnyStorageTrees[0]);\n\n FatIMTPoseidon2WriteEvent.reset(fatEventTrees[0]);\n SkinnyIMTPoseidon2WriteEvent.reset(skinnyEventTrees[0]);\n }\n\n function insert(uint256 leaf) public {\n FatIMTPoseidon2WriteStorage.insert(fatStorageTrees[0], leaf);\n SkinnyIMTPoseidon2WriteStorage.insert(skinnyStorageTrees[0], leaf);\n\n FatIMTPoseidon2WriteEvent.insert(fatEventTrees[0], leaf);\n SkinnyIMTPoseidon2WriteEvent.insert(skinnyEventTrees[0], leaf);\n }\n\n function insertMany(uint256[] calldata leaves) public {\n FatIMTPoseidon2WriteStorage.insertMany(fatStorageTrees[0], leaves);\n SkinnyIMTPoseidon2WriteStorage.insertMany(\n skinnyStorageTrees[0],\n leaves\n );\n FatIMTPoseidon2WriteEvent.insertMany(fatEventTrees[0], leaves);\n SkinnyIMTPoseidon2WriteEvent.insertMany(skinnyEventTrees[0], leaves);\n }\n\n function insertManyRepeated(uint256 value, uint256 amount) public {\n FatIMTPoseidon2WriteStorage.insertManyRepeated(\n fatStorageTrees[0],\n value,\n amount\n );\n SkinnyIMTPoseidon2WriteStorage.insertManyRepeated(\n skinnyStorageTrees[0],\n value,\n amount\n );\n\n FatIMTPoseidon2WriteEvent.insertManyRepeated(\n fatEventTrees[0],\n value,\n amount\n );\n SkinnyIMTPoseidon2WriteEvent.insertManyRepeated(\n skinnyEventTrees[0],\n value,\n amount\n );\n }\n\n function update(\n uint256 oldLeaf,\n uint256 newLeaf,\n uint256 index,\n uint256[] calldata proofSiblings\n ) public {\n FatIMTPoseidon2WriteStorage.update(fatStorageTrees[0], newLeaf, index);\n SkinnyIMTPoseidon2WriteStorage.update(\n skinnyStorageTrees[0],\n oldLeaf,\n newLeaf,\n index,\n proofSiblings\n );\n\n FatIMTPoseidon2WriteEvent.update(fatEventTrees[0], newLeaf, index);\n SkinnyIMTPoseidon2WriteEvent.update(\n skinnyEventTrees[0],\n oldLeaf,\n newLeaf,\n index,\n proofSiblings\n );\n }\n\n function updateMany(\n uint256[] calldata oldLeaves,\n uint256[] calldata newLeaves,\n uint256[] calldata leafIndexes,\n uint256[] calldata proofSiblings\n ) public {\n FatIMTPoseidon2WriteStorage.updateMany(\n fatStorageTrees[0],\n newLeaves,\n leafIndexes\n );\n SkinnyIMTPoseidon2WriteStorage.updateMany(\n skinnyStorageTrees[0],\n oldLeaves,\n newLeaves,\n leafIndexes,\n proofSiblings\n );\n\n FatIMTPoseidon2WriteEvent.updateMany(\n fatEventTrees[0],\n newLeaves,\n leafIndexes\n );\n SkinnyIMTPoseidon2WriteEvent.updateMany(\n skinnyEventTrees[0],\n oldLeaves,\n newLeaves,\n leafIndexes,\n proofSiblings\n );\n }\n\n function _assertRootMatch() private view returns (uint256) {\n uint256 fatStorageRoot = FatIMTPoseidon2Read.root(\n fatStorageTrees[0].treeData\n );\n uint256 fatEventRoot = FatIMTPoseidon2Read.root(fatEventTrees[0]);\n uint256 skinnyStorageRoot = SkinnyIMTPoseidon2Read.root(\n skinnyStorageTrees[0].treeData\n );\n uint256 skinnyEventRoot = SkinnyIMTPoseidon2Read.root(\n skinnyEventTrees[0]\n );\n require(\n fatStorageRoot == fatEventRoot,\n \"fatStorageRoot does not match fatEventRoot\"\n );\n require(\n fatStorageRoot == skinnyStorageRoot,\n \"fatStorageRoot does not match skinnyStorageRoot\"\n );\n require(\n fatStorageRoot == skinnyEventRoot,\n \"fatStorageRoot does not match skinnyEventRoot\"\n );\n return fatStorageRoot;\n }\n\n function root() public view returns (uint256) {\n return _assertRootMatch();\n }\n}\n"
255
+ }
256
+ }
257
+ }
258
+ }