@aztec/protocol-contracts 5.0.0-nightly.20260410 → 5.0.0-nightly.20260412

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.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "transpiled": true,
3
- "noir_version": "1.0.0-beta.19+c09ce9a7dbec1708a8b167fad7411ece61d8b9ea",
3
+ "noir_version": "1.0.0-beta.19+842974fcf034b0a652631e69fc24f92f9ddd1d37",
4
4
  "name": "AuthRegistry",
5
5
  "functions": [
6
6
  {
@@ -56,7 +56,7 @@
56
56
  }
57
57
  },
58
58
  "bytecode": "JwACBAEoAAABBIBHJwAABEclAAAATicCBQQDJwIGBAAfCgAFAAYARBwARkYBLQhEAi0IRQMtCEYEJQAAAHQnAgIERycCAwQAOw4AAwACLAAAQwAwZE5y4TGgKbhQRbaBgVhdKDPoSHm5cJFD4fWT8AAAACYeAgAFAB4CAAUAHgIABgEKIgZDBxYKBwgcCggJAAQqCQYIJwIGAQAKKgcGCSQCAAkAAACxJwIKBAA8BgoBCioIBQckAgAHAAAAwyUAAAH4JwIFAAIpAgAHAO9SU00rAgAIAAAAAAAAAAADAAAAAAAAAAAtCAEJJwIKBAUACAEKAScDCQQBACIJAgotCgoLLQ4HCwAiCwILLQ4FCwAiCwILLQ4CCwAiCwILLQ4ICy0IAQInAgUEBQAIAQUBJwMCBAEAIgkCBQAiAgIKPw8ABQAKJwIFBAEAKgIFCS0LCQknAgIAAAoqCQIKCioKBgskAgALAAABbiUAAAIKLQgBCicCCwQFAAgBCwEnAwoEAQAiCgILLQoLDC0OBwwAIgwCDC0OCQwAIgwCDC0OAwwAIgwCDC0OCAwtCAEDJwIHBAUACAEHAScDAwQBACIKAgcAIgMCCD8PAAcACAAqAwUHLQsHBwoqBwIDCioDBgIkAgACAAAB7CUAAAIKHAoEAgAwCgACAAcmKgEAAQXBUDSsJUi8UTwEAgEmKgEAAQW6uyHXgjMYZDwEAgEm",
59
- "debug_symbols": "tVfbbuJADP2XPPMwvszF/ZXVqqI0rZAQoBRWWlX8+3rKOJdKM2Jh9wVOziQnHvvYST671/7l/P683b8dPrqnH5/dy7Dd7bbvz7vDZn3aHvbKfnYu/wCE7olWHSB0TzH/6zGAAlIC8gqFAtiVJfYF+Mz4DHwBwZiQCohkICoIChIWIM6AXo56C3TOgBRAxhAbsCU2ho3xxvhUQEADsYAIBkIByW6RLIyUBTVmFDKQroAcGTAGjAFjMIcRMpACyBjK5yQFTAaM8cYEMJBrkwWjM+ALSMYkY8QYYQPpCjjHfAWxAEAD5Rac638FWTBmIAXk4K/AGDaGjfHGZANQysAb0HPYKYhswJgUCxCNhzmDzMTLZdWZV59PQ99nq87Mq5Y+rod+f+qe9ufdbtX9Wu/OXyd9HNf7r//TetBV1e73r/qvgm/bXZ/RZTVd7eqXqvN8uRoJ/SigHbOQgIaE04ybhtMUjyIhLTSwoRGTKQhPQUS6eR8hBVOIKVX3wXUJYrZUkNZ1lIi4UPD/IBPhP2aCwKFtAyBWM5HqEto4lkzWoVfLhDR2AT4P0+s+wGOoZQJaO2GxjYR6KtpRMExRCFWjaFiT0U25kFHB35XM2T6+JRMazhQwYwpO1ma4yxJUb/KGhJbQYvAok6v8ctJAbEhAnn1XCZh5G92yoNBIpj7FbCMyZYLSt3I2PCHTwBNinDT8sqLYSIY4NnOLE1fXgJa5TYJm4wrDsiLYmpkQZTR3ivdpII1jEyPXNbhV1zDWFd008yDdHIYWc8yGCFTDaNrLSZrC8FV7YWxOnNFf3sWqxo2Non1XaxSUxxuF3KONQvB4oxA+3ihEjzYK8eON0tS4sVEoPNworTBubZSmvW5sFGposNbCHmo817jviUJUbRRuWDSKs2xEQalGwa3Rw258R1Dsq+9sTK3KTg/HWbfJX4XheAqj/sLEjfdPIormUv0YI6yKNFxKIY6BRPDL966ferjebIfFN/Yliw3b9cuuL4dv5/1mtnr6fbQV+0Y/DodN/3oe+qw0/1DXzx7xK4k/L/lufwA="
59
+ "debug_symbols": "tZfbbuJADIbfJddcjA9zcF9ltaooTSskBCiFlVYV776eMs6h0oxY2L2BD4f88di/J8ln99q/nN+ft/u3w0f39OOzexm2u932/Xl32KxP28Neo5+dyx8AoXuiVQcI3VPM3/obQIE0APkIhQLsyiH2BXyO+Ay+QLBISAUiGUSFoJCwgDgDPR31EuicgRQgixAb2CG2CFvEW8SnAgENYoEIBqFAskskSyNlQc0ZhQzSFciRgUXAImARzGmEDFKALEL5P0mBycAi3iIBDHJvsmB0Br5AskiyiFhE2CBdgXPOV4gFAA3KJTj3/wpZMGaQAjn5K1iELcIW8RbJBqCUwRvof9gpRDawSIoFRPNhzpAj8XJZdebV59PQ99mqM/OqpY/rod+fuqf9ebdbdb/Wu/PXnz6O6/3X92k96FHV7vev+q2Cb9tdn+myms529VPVeb6cjYR+FNCJWUhAQ8KxR9NwHMIoEtJCAxsaMZmC8JREpJvXEVIwhZhSdR1clyBmKwVpX0eJiAsF/w8qEf5jJQic5UAAsVqJVJfQwbFism56tUpIYxV62rgO8BFqlYDWSlhsIaFeinYWkysgUKpm0bAmo5tqIaOCv6uYs3V8KyY0nClgxhSc1sBwlyWoPuQNCY/BcvAok6v8cqeB2JCAvPddJWDmbXTLhkKjmHoXs4XIVAlK39rZ8IRMG54Q46Thlx3FRjHEMZmGE1fXgJa5TYJm2xWGZUewtWdCnMyd+D4NJEsDdQuta3CrrzD11U+TDunmNEgijH2NUk2jaS8naXSo81V7YWzuOKO/vItVjRsHReeuNigojw8KuUcHheDxQSF8fFCyCR8bFOLHB6WpceOgUHh4UFpp3DooTXvdOCjU0GDthd3UeK5x3x2FqDoo3LBoFGdNiYJSzYJbWw+DG0vKANUnFaZWZ6eb42za5G/ScIHHNFyqPjpy4/lTX8DInK4sWBVpuJRCGh8WItLyueun/lxvtsPiHfuSxYbt+mXXl59v5/1mdvT0+2hH7B39OBw2/et56LPS/EVdX3vEryT+vOSr/QE="
60
60
  },
61
61
  {
62
62
  "name": "consume",
@@ -111,8 +111,8 @@
111
111
  }
112
112
  }
113
113
  },
114
- "bytecode": "JwACBAEoAAABBIBIJwAABEglAAAASScCBAQCJwIFBAAfCgAEAAUARS0IRQItCEYDJQAAAHgtAgJHJwIDBEcnAgQEATsOAAQAAykAAEMAR9rNcywAAEQAMGROcuExoCm4UEW2gYFYXSgz6Eh5uXCRQ+H1k/AAAAAmHgIABAAeAgAEACcCBAABKQIABQDvUlNNKwIABgAAAAAAAAAAAwAAAAAAAAAALQgBBycCCAQFAAgBCAEnAwcEAQAiBwIILQoICS0OBQkAIgkCCS0OBAkAIgkCCS0OAgkAIgkCCS0OBgktCAEEJwIIBAUACAEIAScDBAQBACIHAggAIgQCCT8PAAgACScCBwQBACoEBwgtCwgIJwIEAAAKKggECScCCgEACioJCgskAgALAAABMiUAAAQjHgIACQAvKgAIAAkACxwKCwkCHAoJCAAcCggJAhwKCQsBHAoLCAIcCggJAQoqCQoIJAIACAAAAW8lAAAENR4CAAgBCiIIRAkWCgkLHAoLDAAEKgwICwoqCQoIJAIACAAAAZ0nAgwEADwGDAEeAgAIAx4CAAkEKQIADADDt7IGKwIADQAAAAAAAAAABQAAAAAAAAAALQgBDicCDwQFAAgBDwEnAw4EAQAiDgIPLQoPEC0ODBAAIhACEC0OCxAAIhACEC0OCBAAIhACEC0ODRAtCAEIJwILBAUACAELAScDCAQBACIOAgsAIggCDD8PAAsADAAqCAcLLQsLCwAqCwkMLQIIAycABAQFJQAABEctCAUJACoJBwstDgwLJwILBAIAKggLDC0LDAwAKgwDCC0CCQMnAAQEBSUAAARHLQgFAwAqAwsMLQ4IDC0IAQgnAgkEBQAIAQkBJwMIBAEAIgMCCQAiCAILPw8ACQALACoIBwMtCwMDJwIIAAItCAEJJwILBAUACAELAScDCQQBACIJAgstCgsMLQ4FDAAiDAIMLQ4IDAAiDAIMLQ4CDAAiDAIMLQ4GDC0IAQInAggEBQAIAQgBJwMCBAEAIgkCCAAiAgILPw8ACAALACoCBwgtCwgICioIBAsKKgsKDCQCAAwAAAMpJQAABCMtCAELJwIMBAUACAEMAScDCwQBACILAgwtCgwNLQ4FDQAiDQINLQ4IDQAiDQINLQ4DDQAiDQINLQ4GDS0IAQMnAgUEBQAIAQUBJwMDBAEAIgsCBQAiAwIGPw8ABQAGACoDBwUtCwUFCioFBAYKKgYKByQCAAcAAAOnJQAABCMeAgAGAC8qAAUABgAHHAoHCAIcCggGABwKBgcCHAoHCAEcCggGAhwKBgcBJwIGAQEkAgAHAAAD5CUAAAShLQsJBgAiBgIGLQ4GCS0LAgYAIgYCBi0OBgItCwsCACICAgItDgILLQsDAgAiAgICLQ4CAzAKAAQABS0IQwImKgEAAQW6uyHXgjMYZDwEAgEmKgEAAQVMr1JlAlqXtDwEAgEmLQEDBgoABgIHJAAABwAABJwtAAEFAAABBAEAAAMECS0AAwotAAULIwAABIUtAQoILQQICwAACgIKAAALAgsMAAoJDCQAAAwAAARzJwEFBAEjAAAEoC0AAwUmKgEAAQXtK68NmiE35zwEAgEm",
115
- "debug_symbols": "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"
114
+ "bytecode": "JwACBAEoAAABBIBIJwAABEglAAAASScCBAQCJwIFBAAfCgAEAAUARS0IRQItCEYDJQAAAHgtAgJHJwIDBEcnAgQEATsOAAQAAykAAEMAR9rNcywAAEQAMGROcuExoCm4UEW2gYFYXSgz6Eh5uXCRQ+H1k/AAAAAmHgIABAAeAgAEACcCBAABKQIABQDvUlNNKwIABgAAAAAAAAAAAwAAAAAAAAAALQgBBycCCAQFAAgBCAEnAwcEAQAiBwIILQoICS0OBQkAIgkCCS0OBAkAIgkCCS0OAgkAIgkCCS0OBgktCAEEJwIIBAUACAEIAScDBAQBACIHAggAIgQCCT8PAAgACScCBwQBACoEBwgtCwgIJwIEAAAKKggECScCCgEACioJCgskAgALAAABMiUAAAQjHgIACQAvKgAIAAkACxwKCwkCHAoJCAAcCggJAhwKCQsBHAoLCAInAgkCAAoqCAkLJAIACwAAAW8lAAAENR4CAAgBCiIIRAsWCgsMHAoMDQAEKg0IDAoqCwoIJAIACAAAAZ0nAg0EADwGDQEeAgAIAx4CAAsEKQIADQDDt7IGKwIADgAAAAAAAAAABQAAAAAAAAAALQgBDycCEAQFAAgBEAEnAw8EAQAiDwIQLQoQES0ODREAIhECES0ODBEAIhECES0OCBEAIhECES0ODhEtCAEIJwIMBAUACAEMAScDCAQBACIPAgwAIggCDT8PAAwADQAqCAcMLQsMDAAqDAsNLQIIAycABAQFJQAABEctCAULACoLBwwtDg0MJwIMBAIAKggMDS0LDQ0AKg0DCC0CCwMnAAQEBSUAAARHLQgFAwAqAwwNLQ4IDS0IAQgnAgsEBQAIAQsBJwMIBAEAIgMCCwAiCAIMPw8ACwAMACoIBwMtCwMDJwIIAAItCAELJwIMBAUACAEMAScDCwQBACILAgwtCgwNLQ4FDQAiDQINLQ4IDQAiDQINLQ4CDQAiDQINLQ4GDS0IAQInAggEBQAIAQgBJwMCBAEAIgsCCAAiAgIMPw8ACAAMACoCBwgtCwgICioIBAwKKgwKDSQCAA0AAAMpJQAABCMtCAEMJwINBAUACAENAScDDAQBACIMAg0tCg0OLQ4FDgAiDgIOLQ4IDgAiDgIOLQ4DDgAiDgIOLQ4GDi0IAQMnAgUEBQAIAQUBJwMDBAEAIgwCBQAiAwIGPw8ABQAGACoDBwUtCwUFCioFBAYKKgYKByQCAAcAAAOnJQAABCMeAgAGAC8qAAUABgAHHAoHCAIcCggGABwKBgcCHAoHCAEcCggGAgoqBgkHCioHCgYkAgAGAAAD5CUAAAShLQsLBgAiBgIGLQ4GCy0LAgYAIgYCBi0OBgItCwwCACICAgItDgIMLQsDAgAiAgICLQ4CAzAKAAQABS0IQwImKgEAAQW6uyHXgjMYZDwEAgEmKgEAAQVMr1JlAlqXtDwEAgEmLQEDBgoABgIHJAAABwAABJwtAAEFAAABBAEAAAMECS0AAwotAAULIwAABIUtAQoILQQICwAACgIKAAALAgsMAAoJDCQAAAwAAARzJwEFBAEjAAAEoC0AAwUmKgEAAQXtK68NmiE35zwEAgEm",
115
+ "debug_symbols": "vZrdbhs5DIXfxde5kCiKFPsqRVGkqVsYMJzATRZYFHn3JT3ijB1AysRy9ib+wrHP6OdQ0tD+u/m5/fHy+/vu8Ovxz+bL17+bH8fdfr/7/X3/+HD/vHs8aPTvJtifCPqS7vQ1b76wvib9P6JBroBYgTxCUoH9EnukeKR4RJIDTwABHKhCjA71FgDBwQTJoFRIycEj6BH0SPZItmZov4DQwSNs7xGDUqF4pHhEaiSF6KBthqxgbQY2UEGwS9bUCTySNJKCgVSwwUzRQCpkjxA46EAluwVbxG7BXKHEeqlQBbGI3UtoAgzoIBWi9gLBQPuF+ikEjWS9FyaokD2SuQL5JfIIe4Q9Yu2ZIFeQ4IAOMkEOyaFUiCaYDKgCRAePJI8kj6BH0JqhJskZHOw92sFMsUbMtCfg4DBHpIKZdgJrmNom27xPUCNkps1swDViBpiAKoBHLJlOYNk0gd1CDEoFM+0EHskeyR4hj5hpSf1DlnET6HvI2mOmnYArCDjUCAdw8Ig1foJcwTJuAnSQCik51JsymqAYUIUcHTxCHiGPsEfMP6y94AIO+h5Wi7L5eYIaKebnCbQ9rB8v5ucJSgXwCHgkeSRxBbPNBFQhB4fs4Lew5WICFSzq1WLmn4ArFI8Uj4hHpEbEPF/AoFQwzxc04ArgEXPLBNoe0WER1IjYp8wkYpfMJBN4xEwi2aBUsJVNyMAiOl9iJjmBDe8EtvYGW5dDCAvmBW2dDGRo4+1YZrRmx5hOSDNaujqaWMwnlBlP20lFE4Pw+nq38Z3p+/Nxu7WN6Wyr0g3s6f64PTxvvhxe9vu7zT/3+5fTm/483R9Or8/3R72qI7Y9/NRXFfy122+NXu+WT4f2RyGFXD8NCfIsECNdSMSORMAMrhGQaBahcqEBHQ0uriC4NILT6n5QIVfgUpr9wLaE7lE+FAlpGQqGC4V8g5GgTxyJRMUVEsdFIl96orQVsh59qkKOZ42AcNkI6fSiuCeTLJORyuUwxE43ZDGmJIRFI+dLjY4zJWByjSChrQE9V7hEOrMV0Jv0SJ2xiDxbU8+J12no6c811Optjdyb1rhMa46Lt8rqZiThOM8rS7MZPXMFcXtmCLlprtjRwDRbHPFc402yr82SlFpZAh0JisXHkyBIsxXQcWgCYl8xlCU1186eRaMIziIhxqZIusUqjqOL1zt9QVn6crYjvW1GZw3V/J5tqgfYdkP6M0PLzHAozYaUnkXYHZLOljChDyjQrMBNhb7R42L03DJ6T6HAvC8WDC2F1JlVjODdwJibW2vqrqI5z+aKmZsmT90tfvYWtf35TjOWg0bUp5pmMzr+RAjLaCwLR75uPM968nY8O8aSOG+vsHQC43pXZJpdwdxyBfbObPpk7POhnLE1ltjJU5Q8b2pw1XmpyLzDS2zuBNgzhT5kLx1haK7i2PGmPrp7R86G8yMd4bJ0JDfzFHuHT63l4Pw4kPjs9HjpLOTxkxuW8ZMbyujJLYfxk1tXY+XJLcPwya3bjAyLQ892kg91JWOcNShdp0HgWyLQ2Xb0MY1l2SC6TkNTfT4y6YmjrVE+dVrWHqj7EvNhOMRm2lMcf+AjGH3iozS+bhCOrxuUR9cNovF1o6uxct2gcYP2mrHWoF17rXzk49g9uc3+yoGbGmsTBZonFk7jicI4miicxxOFaTxRmEcThct4onQ1ViZKCcOJ0mvG2kTp2mtlopT0ubWR80RBalYQ83htpNANaiOFb1AbKeUGtZEio7WRd/qyrjYicbw28s7MrKuNSBqtjfQV1tRGViogXFNdwUAyp0q5prqCpy+N6qM8NhXkFvX6GxTsb1GxD7co2Yfxmn24RdE+3KJqH8bL9mstRtCyWAw87rEYyrjJ5BZfC4UbmCzGYZP1vltabbKuyFqTRfzfTFbaJoudfYUluAYLtE8NMXZPpYHmHV8X5eZmHXtfMSWd3rm+qQ8f0FaRbvF93ifPy4Knzfab/nv/sDte/Drt1cSOu/sf+23999fL4eHs6vO/T37Ff932dHx82P58OW5NafmJm/75CpqO6opvdxv74ctX0OILgHx7tbv/Bw=="
116
116
  },
117
117
  {
118
118
  "name": "is_consumable",
@@ -164,8 +164,8 @@
164
164
  }
165
165
  }
166
166
  },
167
- "bytecode": "JwACBAEoAAABBIBGJwAABEYnAgQEAicCBQQAHwoABAAFAEMtCEMCLQhEAyUAAABELQICRScCAwRFJwIEBAE7DgAEAAMeAgAEAB4CAAQAHgIABAknAgUBASQCAAQAAABlJQAAAnYnAgQAASkCAAUA71JTTSsCAAYAAAAAAAAAAAMAAAAAAAAAAC0IAQcnAggEBQAIAQgBJwMHBAEAIgcCCC0KCAktDgUJACIJAgktDgQJACIJAgktDgIJACIJAgktDgYJLQgBBCcCCAQFAAgBCAEnAwQEAQAiBwIIACIEAgk/DwAIAAknAgcEAQAqBAcILQsICCcCBAAACioIBAknAgoBAAoqCQoLJAIACwAAARUlAAACiB4CAAkALyoACAAJAAscCgsJAhwKCQgAHAoICQIcCgkLARwKCwgCHAoICQEWCgkIJwIJAAItCAELJwIMBAUACAEMAScDCwQBACILAgwtCgwNLQ4FDQAiDQINLQ4JDQAiDQINLQ4CDQAiDQINLQ4GDS0IAQInAgkEBQAIAQkBJwMCBAEAIgsCCQAiAgIMPw8ACQAMACoCBwktCwkJCioJBAIKKgIKCyQCAAsAAAHHJQAAAogtCAECJwILBAUACAELAScDAgQBACICAgstCgsMLQ4FDAAiDAIMLQ4JDAAiDAIMLQ4DDAAiDAIMLQ4GDC0IAQMnAgUEBQAIAQUBJwMDBAEAIgICBQAiAwIGPw8ABQAGACoDBwItCwICCioCBAMKKgMKBCQCAAQAAAJFJQAAAogeAgADAC8qAAIAAwAEHAoEAwIcCgMCABwKAgMCHAoDBAEcCgQCAhwKAgMBBCoIAwImKgEAAQXwQ+Wh+qIsNDwEAgEmKgEAAQW6uyHXgjMYZDwEAgEm",
168
- "debug_symbols": "tVhbbuM4ELyLvv3BZj9I5iqDQeAkzsCA4QQee4FF4LsvO2JLcgByNUPnJyqXpFKTrGox+hhedk+XX4/74+vb7+Hhx8fwdNofDvtfj4e35+15/3bM7Mfg9I/E4QE3Q8DhIeRD/gVuM8T8EyAf43hMMh7BQQZRgRQAXAAaQ86AnWJj2BgxRshALEBLGUEoIHoD9ohkZaQs6J2CNALvyIAxYAwY443BXIYHBVwAGUN6DSpIBbAxbIwYE7yBXLNPGWjNqDopC6Ke0lIVoHMGjAFjwBivZZCC/AhyClIBiAZiAWQMGcPGcChAwIAUEJwBNmCPiPZQXX/yGSRvIIyAnDdgDBgDxngtAxXEAlCvYQWhADJGTTKCXA/r7TrPn0DneQTGBGOCMWrZEYQCtOYRyAhY3TuC8gjWmR+BCpKCWIAWPwJj0Bg0hoxRk3AuntUkI9BrcqRY0IAxQQqIuR5BBZkRvSvl20VPqZ8ViCMDxoAxYIyaROL1uhks4I/n026n+V4kPveB9+1pdzwPD8fL4bAZ/tkeLp8X/X7fHj+P5+0pn80rvzu+5GMWfN0fdoqum/luV781J4rL3R49TwIAciMBDQmXLWUajjxMIp9DnDV8QyNEU0g0FxFw9TgkiimEGKvjoLoEEtlUIMk8FcHfKPAdZkK+cSYQQ5iG4ag6E7Eh4VIC08ivEF8bR6prgItUJABc6B+JVEfSkOA42ZsjzuvBtwGBhjVzp7GBMCyWxLvbgQA2FjVaRDHN3szd+lahYc405zQhzQuCzLcaDXsmpy191HDJ1TWkFRKTwEXKvHzpFqExFxCSORxi+DsNj1PafaC6Rmqtq0zr6t1sDYiry8iLOc1GTky9jJa9XIpzGVy1l29oUF6LokG01PjLoLCrBcU3LCowJV7yZq5ahW9YFL3oZI1T6gWx+i5peRRyRKb2lbj+Qgr3eKvF3mbeHkuMaR7L4rX0pQxsNVKeU8utQtor4xYrQ7FaiG9ZxKZUcNHD0h/YVMJk05RqNkXq7+fIvf0cpb+fY+jv5xh7+zmm/n7e1FjZzwm6+3mrjLX9vGmvlf2cmjvRNPmLF3unrxorg5JAakEh6Q8Khd6gUOwPCqX+oLDrDQpDf1CaGiuDwtgdlFYZa4PStNfKoLB888ZnERTkWlA49m98ON1h4yPuDhsfuce/89L9/3x7LCs3PkL9G5//WZl1Gx+Rb934OJptGm5s+jP/2j7vTzdfi6+qddpvnw678vP1cnxenD3/+25n7Gvz++ntefdyOe1Uaf7kDPmr1w/Iu1Tw8edVn/cf"
167
+ "bytecode": "JwACBAEoAAABBIBGJwAABEYnAgQEAicCBQQAHwoABAAFAEMtCEMCLQhEAyUAAABELQICRScCAwRFJwIEBAE7DgAEAAMeAgAEAB4CAAQAHgIABAknAgUBASQCAAQAAABlJQAAAn8nAgQAASkCAAUA71JTTSsCAAYAAAAAAAAAAAMAAAAAAAAAAC0IAQcnAggEBQAIAQgBJwMHBAEAIgcCCC0KCAktDgUJACIJAgktDgQJACIJAgktDgIJACIJAgktDgYJLQgBBCcCCAQFAAgBCAEnAwQEAQAiBwIIACIEAgk/DwAIAAknAgcEAQAqBAcILQsICCcCBAAACioIBAknAgoBAAoqCQoLJAIACwAAARUlAAACkR4CAAkALyoACAAJAAscCgsJAhwKCQgAHAoICQIcCgkLARwKCwgCJwIJAgAKKggJCycCCAACLQgBDCcCDQQFAAgBDQEnAwwEAQAiDAINLQoNDi0OBQ4AIg4CDi0OCA4AIg4CDi0OAg4AIg4CDi0OBg4tCAECJwIIBAUACAEIAScDAgQBACIMAggAIgICDT8PAAgADQAqAgcILQsICAoqCAQCCioCCgwkAgAMAAAByCUAAAKRLQgBAicCDAQFAAgBDAEnAwIEAQAiAgIMLQoMDS0OBQ0AIg0CDS0OCA0AIg0CDS0OAw0AIg0CDS0OBg0tCAEDJwIFBAUACAEFAScDAwQBACICAgUAIgMCBj8PAAUABgAqAwcCLQsCAgoqAgQDCioDCgQkAgAEAAACRiUAAAKRHgIAAwAvKgACAAMABBwKBAMCHAoDAgAcCgIDAhwKAwQBHAoEAgIKKgIJAxYKAwIEKgsCAy0KAwImKgEAAQXwQ+Wh+qIsNDwEAgEmKgEAAQW6uyHXgjMYZDwEAgEm",
168
+ "debug_symbols": "tZjRbuM4DEX/xc95EEWRkvorg0GRtu4gQJAWmWSBRZF/X7IW7WQAqd4q81Kf0PY1ZfGKqj+Gl/Hp/Otxd3h9+z08/PgYno67/X7363H/9rw97d4OEv0YnP7hNDzgZog4PEQ5yC9wmyHJTwA5pumYeTqCA4GkwAWACqBFgjOwU2QRsghbhINBKqCpTBALJG9gj8iWRhZB7xTyBN4FA4uARcAi3iIoaXhQoALBIkGvQYVcgCxCFmGLRG8gOfssoDmj6mQRRD2lqSqgcwYaCQLgDDRCAt4ZSCR4AU11gmCQCwSLBIuQRSgVYG8QC0Qw4ALJHpHsoUkFNbGMBmmC4NDAImARsIi+50AKuQDqNVEhFQgWITCQfEhv1yKZgApEi0SLJIukYJAKaM4TxAnIeYPyCAIwUEFWyAU0+QksghZBiwSLaIVTVCADvUYqgbRIJrCIFsknaJEwKUiE9S4tEpZTrEUygUW0SKJToAJaJBEUyEAeEf3lshnM6Y+n4ziq0a+sLwvC+/Y4Hk7Dw+G832+Gf7b78+dFv9+3h8/jaXuUs/KQ8fAiRxF83e1HpctmudvVbxVrUbnbSxHPAgB8IwENCRfIm4YLzLMIpxsN39CIyRRyWJKIuHocnNgUYkrVcYS6hPjTXgVKKc8SnxO1KNAd3gT/xTeBGOM8DBeqbyI1JMAFy0KYc20cua4Bbp4QAJf7R8LVkTQkKM3lTQlhlqBbg0CjNAl0jZwk4GpKvLsdCGBjUpNZVBbmWQHT7duERnHmxacZg180iG41GuWZXUDTcNnVNbhlEpPAK5d5/mO1iI13AXF2KqTwPQ2PloYX59c1cmteYZlXWkoD0uo0MOtqXuY15noarfJy2axG3lG1vHxDQ7q0aYRwrfFNo5CrGcU3SpRlNouEtLxczcI3ShQ9R1tBhTNWe0mrRmWXGWYRB1AViffoaql3Mf9iLCEvY7nq0H+kga2FlGiuU3a+nkh7ZniZmehSNRHfKhFb0Bmv1rDM/0OBZ4XYqxDqOTStwnG2Ss41qyD39xSMvT0FU39PwdzfU4Lr7SkB+ntKU2NlTwnY3VNaaaztKc3yWtlTQrPR57m+yMWqxkqjZOCaUULqN0rIvUYh128Ugn6jkO81CmG/UZoaK41C1G2UVhprjdIsr5VGofSXN19XRkGqGYVd/+aL4Q6bL/Z32Hwx3uMf6dC7+fpiLOs2X8z9m68vZmbd5otT7+arrbBm87VS4bubLxcWq8Qbq/yUX9vn3fHm8/lFtY677dN+LD9fz4fnq7Onf9/tjH1+fz++PY8v5+OoSss3eP0I+QNkvw/ofl70ef8B"
169
169
  },
170
170
  {
171
171
  "name": "is_reject_all",
@@ -210,8 +210,8 @@
210
210
  }
211
211
  }
212
212
  },
213
- "bytecode": "JwACBAEoAAABBIBFJwAABEUnAgMEAScCBAQAHwoAAwAEAEMtCEMCJQAAAEAtAgJEJwIDBEQnAgQEATsOAAQAAx4CAAMAHgIAAwAeAgADCScCBAEBJAIAAwAAAGElAAABQSkCAAMA71JTTScCBAABKwIABQAAAAAAAAAAAwAAAAAAAAAALQgBBicCBwQFAAgBBwEnAwYEAQAiBgIHLQoHCC0OAwgAIggCCC0OBAgAIggCCC0OAggAIggCCC0OBQgtCAECJwIDBAUACAEDAScDAgQBACIGAgMAIgICBD8PAAMABCcCAwQBACoCAwQtCwQEJwICAAAKKgQCAycCAgEACioDAgUkAgAFAAABESUAAAFTHgIAAgAvKgAEAAIAAxwKAwQCHAoEAgAcCgIDAhwKAwQBHAoEAgIcCgIDAS0KAwImKgEAAQWiP4wWRewq/zwEAgEmKgEAAQW6uyHXgjMYZDwEAgEm",
214
- "debug_symbols": "tZZZauNAEIbvomc91NKrrxJCUBwlCIRsFHtgML77VNsqLYZuQpLxg/tXtfW51pYu1Vv7ev546Yb3w2e1e7pUr2PX993HS3/YN6fuMIj1UkH6cqbacV25WO18XXm5QpBVLhHrKpj7GmlavayhrhDcJBAnwaRCt4xuGbVYtVi1OFBhVMRJeFYRJhH0L4K6EQVIkIS9CwJQoRZUC6qF1ELiBklYxKhCLSb9hpOwk7BqsWpxanFhEslnikmIhRMnCJDTVnL1LiYLA6pQC94s12tdaaFeTmPbpjqtKif1PDZjO5yq3XDu+7r60/Tn248+j81wW0/NKLsSYju8ySrA965vk7rWy92Qv5UY7HQ3MdkZgOg2CCwgwIBXBhjCGeLChkEFhg9KiGZxwvOX43DBKcGHkI3D5BFsjKaCjVtS4WlDsL+QCfcfM8Hs/RwGmGwmQgEBMaIyEJByccQ8AyGYCYEI/ueRuGwkBYS1aUpvCCufGWG3A4KF1rRoNBCLq5IQbANBLhQ16IhyXHqTwzabWGjOuMxpZLMUhCWoDaPQnhEMKwMi5BmuNCSK4NWUkXs4LXwhF+i1JCQH/PcYcn4rg7zJM2Kprm6uK8Eyqhi+7IYUc86GTEzejVJ7QQyLGzbbXlRgGKnFxDBmzfjmoKwy+jAoVGhRh/PEO4KY9YIKLcrkUrLuKSUnz8jcs6TUoygjMh9f0eYfSP43nmrhp4d5OZYQ4hLL6rH04AaXDlK7TK0tOVKuDKwqY0LWESq1iKbU8eoMi9Igz3LZ7Ltx8+p6Taixa177drp8Pw/71e7p71F39NX3OB727dt5bBNpef9Nr1xPjmtnn6/p3/4B"
213
+ "bytecode": "JwACBAEoAAABBIBFJwAABEUnAgMEAScCBAQAHwoAAwAEAEMtCEMCJQAAAEAtAgJEJwIDBEQnAgQEATsOAAQAAx4CAAMAHgIAAwAeAgADCScCBAEBJAIAAwAAAGElAAABRikCAAMA71JTTScCBAABKwIABQAAAAAAAAAAAwAAAAAAAAAALQgBBicCBwQFAAgBBwEnAwYEAQAiBgIHLQoHCC0OAwgAIggCCC0OBAgAIggCCC0OAggAIggCCC0OBQgtCAECJwIDBAUACAEDAScDAgQBACIGAgMAIgICBD8PAAMABCcCAwQBACoCAwQtCwQEJwICAAAKKgQCAycCAgEACioDAgUkAgAFAAABESUAAAFYHgIAAgAvKgAEAAIAAxwKAwQCHAoEAgAcCgIDAhwKAwQBHAoEAgInAgMCAAoqAgMEFgoEAiYqAQABBaI/jBZF7Cr/PAQCASYqAQABBbq7IdeCMxhkPAQCASY=",
214
+ "debug_symbols": "tZbdbusgDMffhetcYGwM9FWmacq6bIoUpVXWHulo6rsf6HA+KsHZWXd6Uf4xyS82tgkf6qV7Pr899ePr4V3tHj7U89QPQ//2NBz27ak/jNH6oXT6Y1I7bBQHtXONcvEKdBzjJUCjPH2OweTRxdE3CjRnAZAFGhEyRTJFYrFisWJhLYJEhCwcivBZeHmFFzdCBBqdhP0URmsRYgGxgFiMWEx0w8SwDIIIsVC6B5OwWVixWLGwWNhnkXw2IYlowcTxEYhpKrn6KbIFdbJQEpxFWky0SXAW5mq5XBolqXs6TV2XMrfKZczwsZ268aR243kYGvWrHc7Xm96P7XgdT+0UZ2PQ3fgSxwh87YcuqUuzPK3LjxrUNj9t0NgZAMAbBFQQmqwRhibmGcJ+wzAVhvNCCLQ44fDLcbBnITjvi3FQGYFEshRIvCyFMxuC/YGV4P+4EojOzWFoKq6EryBAk3gRNYdSHKHMAD0nBECH+yPhYiQVhLWpb68IG38zwm4bBCqlaYFIELBKidHbQAArSfXSohiW2kS/XU2oFGdY+jQgmYVh7ZZRKc+gCYWhgy4zuNYkgsBVlxm+2S1cZS3AzZ0Knr7HMChuxN2+4keo5RWWvFpYqst/2Q0MDua8ulB2o1ZeOkir2fh1K5aXqTAo5iIziNaMbzaKo1KjmEqJcsxmRrBZdfytF6ZSomjYyQ4adcDit6RWoxACzRANUIS4n/iq+Xs387/EQmGJZfWFvnEDaxuptXOdsjZlR+qZ4SUzTvuiI6ZWIrKhM672sMD/QOCZ4O4l0I0Pj/Gy3ffT5kB9Saipb5+HLl++nsf9avb0+ygzciA/Tod993KeukRaTuXpIPjA1DA/XtLb/gA="
215
215
  },
216
216
  {
217
217
  "name": "set_authorized",
@@ -245,7 +245,7 @@
245
245
  }
246
246
  },
247
247
  "bytecode": "JwACBAEoAAABBIBGJwAABEYlAAAASicCBAQCJwIFBAAfCgAEAAUARBwARUUBLQhEAi0IRQMlAAAAcCcCAgRGJwIDBAA7DgADAAIsAABDADBkTnLhMaApuFBFtoGBWF0oM+hIeblwkUPh9ZPwAAAAJh4CAAQAHgIABAAeAgAEAQoiBEMFFgoFBhwKBgcABCoHBAYnAgQBAAoqBQQHJAIABwAAAK0nAggEADwGCAEnAgUAAikCAAcA71JTTSsCAAgAAAAAAAAAAAMAAAAAAAAAAC0IAQknAgoEBQAIAQoBJwMJBAEAIgkCCi0KCgstDgcLACILAgstDgULACILAgstDgYLACILAgstDggLLQgBBScCBgQFAAgBBgEnAwUEAQAiCQIGACIFAgo/DwAGAAonAgYEAQAqBQYJLQsJCScCBQAACioJBQoKKgoECyQCAAsAAAFYJQAAAeItCAEKJwILBAUACAELAScDCgQBACIKAgstCgsMLQ4HDAAiDAIMLQ4JDAAiDAIMLQ4CDAAiDAIMLQ4IDC0IAQInAgcEBQAIAQcBJwMCBAEAIgoCBwAiAgIIPw8ABwAIACoCBgctCwcHCioHBQIKKgIEBSQCAAUAAAHWJQAAAeIcCgMCADAKAAIAByYqAQABBbq7IdeCMxhkPAQCASY=",
248
- "debug_symbols": "tVdbbtswELyLvv3B3eVrfZWiCBxHCQwItqHYBYrAd+/S5uphgIQatT/WeCiNRstZivpq3trX68fL4fh++my2P76a1/7QdYePl+60310Op6OwX41JPwDYbGkjx9BsgxxR/gMkIASkEUIFPg9ZUJAYJ8CBAmW8VcAZBGq2iAnEDGJ4ADSZweTmAXQIlUFlSJnk5w6sUeAUcAbOKtBbeFKQBK2AAAp8BlGZqAwrw5khk2y4BEIGoAykc6SYhKBAGVKGOAMrDikJ2piBIwXKeGW8MgEV+AyS5wdwGbBRoLdgfgBrkqBPIGRwz8EdKIPKoDKkDCUbYt5aUpDOYQEOFSjjXQZB/FhKQBjrb7dNo4F8ufRtm/I4Sajk9rzr2+Ol2R6vXbdpfu266/2kz/PueD9edr2Mmk3THt/kKILvh65N6LYZrzblS5GMy1dLrtwgAOBnElCRMFJE1TAWYRDxcaaBFY0QVYHtaCLQ4ufw0atCiLH4HLYsIUHUUpDM2SARcKbg/kEl/P+sBPnBA0UcJNw8E7GsIK2gtbTgioXgigdZD0lNgENfKgSY2nywTocvV6LuwsLogqnoopJMi2asBY/V/FYxJ8/xVEyoBJNBc8k4JtvC8kSkJS8nwvtSIqCSSgdWJRxMcolmPhsQKjaiVpJ4fAyKT3NRqSWPixWTHaNNbj4dUAkFG6vJZMOmqIHVZKoETZYa9POlBmtrJgQekhnD9zSQhiUPgy1rUG1e/TCvaMb1CuJiGzKZQzWYoWijGi/DcbThivFCX10uhnw5E4oaSxtlMrNPjYJxfaMgr20UMusbhWB9oxCubRSi9Y1S1VjYKORWN0rNxtJGqcZrYaNQ7Y0kc6FvJDvVeNoqLWwUa4qNYisSgY1WIzBy0YWtLT3WDC94wa6437JYm1k3VHTSbfxXNowdbZR3O7a2+yT5klER6RssilRSKlu/wUgAN980/ZS/u/2hn30E35JYf9i9dm3++3497iejl99nHdGP6HN/2rdv175NStMvaflkkWix+XlLd/sD"
248
+ "debug_symbols": "tVfbbtswDP0XP+dBJHVjfmUYijR1iwBGErjJgKHIv49KRF8CSPDq7SU+PrKPKfJQkb6at/b1+vFyOL6fPpvtj6/mtT903eHjpTvtd5fD6SjsV2PSDwA2W9rINTTbIFeUe4AEhIA0QqjA5yELChLjBDhQoIy3CjiDQM0WMYGYQQwPgCYzmKJ5AB1CZVAZUibFcwfWKHAKOANnFegnPClIglZAAAU+g6hMVIaV4cyQSWG4BEIGoAykZySZhKBAGVKGOAMrEVIStDEDRwqU8cp4ZQIq8BmkmB/AZcBGgX6C+QGsSYI+gZDB3Qd3oAwqg8qQMpTCkOCtJQXpGRbgUIEy3mUQJB5LCQhj/e22adSQL5e+bZMfJw4V3553fXu8NNvjtes2za9dd70/9HneHe/Xy66XUbNp2uObXEXw/dC1Cd0249um/CqScflt8ZUbBAD8TAIqEkbmrBrGej+I+DjTwIpGiKrAdgwi0OJ5+OhVIcRYnIctS4gRNRUkNRskAs4U3D/IhP+fmSAfhopGHCTc3BOxrCCtoLm04IqJ4EoM8towDXABSokAU6sHazl8ORP1KEZTgKdYjKLiTItmzAWP2fxWMifzeEomVIzJoL5kHOdgYbkj0pKXHTEx5ZMjoOJKB1YlHEx8iWZeDQiVMKJmknicBsWnWlRyyeNixWRHa5OblwMqpmCTVuCHhmFT1MCqM1WCJksN+vlSg7U1E8LozGi/pyF1VQ1Z/soaVKsrjHV1Y5tCXBwGcYChroGLYVTtZViXC4fGFe2FvrpcDP5yJhQ1ljbKpLJPjYJxfaMgr20UMusbhWB9oxCubRSi9Y1S1VjYKORWN0otjKWNUrXXwkah2j+S1EL/kexU42mrtLBRrCk2iq1IBDZalMDIxShsbemxYIaUWoDiNsNirbJuyOik2/hvwjDeDmGYWNz22druU3pFnS6YsShScakcj3T/KQckmm+afsrtbn/oZ4fgWxLrD7vXrs2379fjfjJ6+X3WET1En/vTvn279m1Smp6k5cgi1mLz85a+9gc="
249
249
  },
250
250
  {
251
251
  "name": "set_authorized_private",
@@ -1416,7 +1416,7 @@
1416
1416
  "name": "pk_m",
1417
1417
  "type": {
1418
1418
  "kind": "struct",
1419
- "path": "std::embedded_curve_ops::EmbeddedCurvePoint",
1419
+ "path": "aztec::protocol_types::point::Point",
1420
1420
  "fields": [
1421
1421
  {
1422
1422
  "name": "x",
@@ -2048,11 +2048,6 @@
2048
2048
  "visibility": "databus"
2049
2049
  },
2050
2050
  "error_types": {
2051
- "3632530479893888919": {
2052
- "error_kind": "fmtstring",
2053
- "length": 98,
2054
- "item_types": []
2055
- },
2056
2051
  "7555607922535724711": {
2057
2052
  "error_kind": "string",
2058
2053
  "string": "Preimage mismatch"
@@ -2064,11 +2059,16 @@
2064
2059
  "14990209321349310352": {
2065
2060
  "error_kind": "string",
2066
2061
  "string": "attempt to add with overflow"
2062
+ },
2063
+ "17110599087403377004": {
2064
+ "error_kind": "fmtstring",
2065
+ "length": 98,
2066
+ "item_types": []
2067
2067
  }
2068
2068
  }
2069
2069
  },
2070
- "bytecode": "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",
2071
- "debug_symbols": "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",
2070
+ "bytecode": "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",
2071
+ "debug_symbols": "tVvbbhs5DP0XP+dBFC+i8ivFokhTtwgQJIGbFFgU/feVZiTN2FnRisd5CenLHFMUSVEk82f3ff/t7efXh6cfz792t1/+7L4dHh4fH35+fXy+v3t9eH5K7/7ZufwHaHeL7u/NDqZXuLv1Mb3y06u4u6XEu5nATPxMcCY0E97dxkRkdwuQaChUC40zRVcoFOoLxUITGvhEuVApNBSqhcaZkisUCvWFYqEFjwoeFTwqeFTwqOBxweOCxwWPCx4XPC54XPC44HHG00TjTMUVmvGSfiTjZfViVm9ebVmsT+9Rfi/r2sOs7In6QrFQKpQLTRJ4mjU+US00SeB51vhEodCMF2aNTzTjhfTrPG14fjrJmzc+00kaLdJokUaLNJqekump/Gk2ofA/q9L6DfibXlX7+/p62O/zJyuDTGb6cnfYP73ubp/eHh9vdr/vHt+mL/16uXua6OvdIX3qbnb7p++JJsAfD4/7zP29WZ52/UeFpTwcXGiPQ6RRANZYAMSvAHRYAqAQQ4EAUi8NhP0RBvYxAnFdReCLhGBQqkKwB+4JwX0M8ogFgtBBQyA4FkP6EBikQqCi70KE7RBqQHipe4pe1xD+Qn166ukTLNt0rNW2nCzGhR9AIN8QmDsI9jqaOtM6ELrrMKwTGao6ZWWd8WQd1EeIBNVFIqF2dwQM84zi6q5GQexjGPbJ4qo+WYD6GIaBeqzhyvPatnBcn75ZuGhXn+5z4iVWk1S3rB9S1BkEUK3Ca9QugPfG8qUGOwyrLXDxGMFQoG/h0q/c6h3CmAyKXQRDDdFXgIjSV4NsXYT7xENDYt3KQHFlhzoeXZy04KJriPFFxLYT6vyyFQDHmkQwxEBdDmB/kRjeQ9WF9yurzBZ6JIZ1iEv1y6DQDS1ohUlsUZLdJceWR6kIPj/W1aZllyDaVLFKiRSOIYK1Drd4By1iIJ+IYRzi0VHdkeii62NEw8tpSSWWWOVFjhDIUGjKg6pC0Xm+DANcNQwENDCMeMUANR3hdKavvH1cDCFZjnG6bCnSMhoUuVClAks6sfL4D2HEpg6Mq9j1DiN8rkpjaEuJoS+G5bFE1Dx2faCeeCxbYThZZt2WxMdlb9PBMg5CLRKDS1eIHoh1l/JcvYX9+jw4XYx1tiuGFsOUVtep08WYIMH7BhJWzj++GApUlUoKSwDi4/OVjVCacm+oOWviCbu3MsNOIZlIS+GTjXBXIWrd7WoIIuBlY/jSpawy35OliJU0QTsW/PoS8AEpiNpRLxRcVwp/hXsubr+lCl0Bg7dfdc8otVlHVmrXSsW6FXnXCikpmSLtguj2vEHi9rwhuK15Q4DteYOJMZg3BNx8yJliDOYNNsZY3mBjjOUNJsZg3hD0c1U6mDfYXisKzWuDdCtUNkgI7WwRxdgDUSOeQpB2eUp8hMtA2LccJnA/CKkRUTlqrC7DMbruUam8+f6jsj2Oadgex1S3xjGN253fxhhzXBNj0HHj9juULcaY49pGuqRBieduth6tWj3ykpt2az9nxBBqtWXX95UYrGoitfxDUjHzMpC0hHpYJp66ChmPH4Fdv2BvXYKwFXch2eoiSPwIRmz3KFrVmN9h+M0xCBxaFUrxLdteBeXTAJIufttbGLg9GIKT7dEQXNgaDsHp9nh4BmQsINoggxERADaHxDOCjMXEM06ztNsMp7EjQFgKGCFEf1EaotBiUeKle40Bq83kPUdYysnQD0ZwhSoqwBXKqACb66jgr1BItUEGb0Tgt6cBtiCjYcBfoRB6xl4DLfYau8MHYLWiUuvRt+JO6md1T2DwVkFVdUkFVk2YDwlCTbGJF+wLYpirOm4VnszTJdU/XSpmytir/oHZl0o9GFgqd2HVj3Gn3Xe/dQjgjCTcEsbEh2BIQmZ7qaUltGrBn6YlyFeIaniNdAC3pwNWk2o4qpkgo1HNakWMRjW8RnJjg4yVes6ADGZIeI0MifiT9TqaIZ1x4bgEE1mFpHcuTLr14nhGEmld5nQgQOxLYjWcQsKplpL4/t0RGK4Q68/IgtrmCIHQ9VGMmw61OUDm9QE4PouYOoANYSXEaf8MmK/QQDuDQi2xSHvj8UIUXtqbmm6QF8uCK5RwIcr2niDT0uBk7M9XWKYmoY3tyKpVO0H8k17e3T8cjse6QXJ352YHIfvvzTTUO9E402mcuwz1Uhnq5TJizGXEmP08YjxRySuZR4y5jBhnzeURYy4jxlxGjLkMdXOcR4wnSoUmPIF5qHuiIU8SzUPdE40zzUPdIc5D3RP1OWWYh7rzCFIe6p4oFyp5xG8e6s4OkYe6J5rwYpyHuieah5AdlKnuNtadA/Y0153LbPNgN9bJbqyj3Vhmu30d7s6Fn2m6e2JguoeW+e6JwcpQZTJyPjBFKhMqk5Epj4dn5Kzy4CqTkbPSQ0bOtfmAlcnI2b4CV0YqEyqTkfMBG2Jh1FUGKjMhp19XLD+qVBmuTEbOrVoNldHKxMLEKnOEyvjKVOSYkSUfJL/vDg933x732WKzUb893VcDTi9f/32pn9T/XHg5PN/vv78d9tnYJzvH8udL2h3E7Avc3pEblPxOOPlO9pn/AA==",
2072
2072
  "verification_key": "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"
2073
2073
  },
2074
2074
  {
@@ -2096,7 +2096,7 @@
2096
2096
  }
2097
2097
  },
2098
2098
  "bytecode": "JwACBAEoAAABBIBFJwAABEUlAAAARicCAwQBJwIEBAAfCgADAAQARBwAREQBLQhEAiUAAABsJwICBEUnAgMEADsOAAMAAiwAAEMAMGROcuExoCm4UEW2gYFYXSgz6Eh5uXCRQ+H1k/AAAAAmHgIAAwAeAgADAB4CAAMBCiIDQwQWCgQFHAoFBgAEKgYDBScCAwEACioEAwYkAgAGAAAAqScCBwQAPAYHASkCAAQA71JTTScCBgABKwIABwAAAAAAAAAAAwAAAAAAAAAALQgBCCcCCQQFAAgBCQEnAwgEAQAiCAIJLQoJCi0OBAoAIgoCCi0OBgoAIgoCCi0OBQoAIgoCCi0OBwotCAEEJwIFBAUACAEFAScDBAQBACIIAgUAIgQCBj8PAAUABicCBQQBACoEBQYtCwYGJwIEAAAKKgYEBQoqBQMEJAIABAAAAVQlAAABYBwKAgMAMAoAAwAGJioBAAEFursh14IzGGQ8BAIBJg==",
2099
- "debug_symbols": "tVbbTuswEPyXPPfBe/Fl+ysIoVICihSlVWiPdIT678cGb5wg2QJ0eGkm62Yynh3beeue+sfry8MwPZ9eu/3dW/c4D+M4vDyMp+PhMpymWH3rTPoBE7o97ToA6vY+XeM9QAQYC5BGMGRAmIfIZ8CpYhPwGVitOKPAKpBujxiBDxkE+gBoWEEeQtAh0ApqBbWS9HwAlwGDApuBNQr0FTbLQJcIOQGfgUcFWglaCVoRrUiSEedFhhRoBdJ/fAI+A9QKaoVsBhwVEiQQK8S3267TNj1c5r5PXVr1LXbzfJj76dLtp+s47ro/h/H6/qfX82F6v14Ocxw1u66fnuI1Ej4PY5/QbVeeNvVHkYzNT0eT7UIA4DYU0KAwbLxyGEZYSFzYcGCDwwdlEC4iPH15Hi44ZfAhVOfBdQpiViuIXbHC44bB/gcn3G864WHpqKcSCbvNRKgzMKB6yWCrRkhDA9i0jXyIiBuFqxkBptUP0Xa4uhNtFQxFhVBVRSOZjKZ4IcXNH5m5mscnM6ERTFkaKliSzfCNtbFkygPXEgGNVFpgzhQWVrlEs+0G+IaMoE6SlGlQ+NSLhpdSNishxsJht+2ARijEsCZTjJgqBzaTqRS02mrQbbcabO2Z4GVJZvA/44iHoXKg5zoHtfrqlr6iKfsVhC/LiM1c3BCBqoxmvIyEIsNW44UNDqYl5cxrjk8nwFcXCkltoWAjol6MuuEFpaoCpRUvs+xbEdvqMUKm1Vm7OLpabfItGYaLjPomTo3tk4i8ppTiusEqSSOl5PwiJJ5u27PgPt4ejsO8+eK9JbJ5ODyOfb59vk7H1ejl71lH9Iv5PJ+O/dN17hPT6rM5fmjeOdg5ur+lt/0D"
2099
+ "debug_symbols": "tVbbbuIwFPyXPPPgc/GNX6mqKkCoIkUBpbDSCvHva7c+cYJki1bbFzI5JpPjmbHjW3Podtf3t348nj6a7cut2U39MPTvb8Np31760xiqt0bFH1Cu2dKmAaBma+M13AMEgKEAcQRdAoRpiGwCHCs6ApuAlopRArQA32wRA7AuAUdfABULSEMIMgRSQamgVGI/X8AkwCBAJ6CVAHmFTm2giYQcgU3AogCpOKk4qXip+NhGmBcpEiAViP+xEdgEUCooFdIJcOiQIIJQIb7fN43Y9HaZui66tPAtuHlup268NNvxOgyb5k87XD//9HFux8/rpZ3CqNo03XgI10B47IcuovsmP63KjyIpnZ4OIuuZAMCsKKBCoVijcCg2ZiYxbsWBFQ7rhMFzbsLS0/MwzgiDda44Dy5TELNIQWyyFBZXDPo/KGF+UwkLs6OWciT0OhOuzMCAoiWDLgrhKz2Ex+ZpgLZQEgJUzQ8vdpiyEvUucijAkCt2UUkmo8pa+Kzmj8RczONBTKgE08+GesxzYPjG2pjNsMClREAllRqYE4WGRS5Rrd0AW2nDiZLk8zTIPXhR0dLnzcoTY+bQazugEgqvmIRDeVXkwGoyhYIWWw2a9VaDtT0TbE6m459xIEkbGCwuc1DNV8i+6rxMwT3dBnkLs6/WF9uoxkt5SahGpYvxwgoH05xy5iXHwxfg2YVCvrRQsBJR65WYYj36Yhfoa/ECNUvKAMXdk1TNWT0rulht/jttKMNzG8oVv2ZU2T4prBVJesAeiySVlJJx8lkli7T+FryG23bfT6sT7z2STX27G7p0e7yO+8Xo5e9ZRuTEfJ5O++5wnbrItDg2h4Pmi4GNodd7fNs/"
2100
2100
  },
2101
2101
  {
2102
2102
  "name": "utility_is_consumable",
@@ -2151,8 +2151,8 @@
2151
2151
  }
2152
2152
  }
2153
2153
  },
2154
- "bytecode": "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",
2155
- "debug_symbols": "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"
2154
+ "bytecode": "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",
2155
+ "debug_symbols": "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"
2156
2156
  },
2157
2157
  {
2158
2158
  "name": "offchain_receive",
@@ -2290,7 +2290,7 @@
2290
2290
  }
2291
2291
  },
2292
2292
  "bytecode": "H4sIAAAAAAAA/+2dd3xUxRbHk9300El200xBwV6QYlcggIIgSoioqLgmS1gJSUg2SECEFbCiJgHsFUhAERt2sHc5Y++CitixY8X2JsjuTu69M7t38+P5ee8z/HWS2fmec+fMnJkzezlxNjddeWf1pEllkz2+qom13jKvb7qXxQ9qCqwaUuurrPRVFHsqKxfHNQdaBtfWeho2xA9a1NjU/FRhnPpffFzEj8RFB4pHgRwokBMFSkCBElGgJBQoGQVKQYFSUaA0FCgdBeqEAnVGgbqgQF1RoG4oUHcUqAcK1BMFykCBMlEgFwrkRoGyUKBsFCgHBcpFgfJQoF1QoHwUqAAFKkSBilCgXijQrijQbihQbxSoDwq0Owq0Bwq0Jwq0Fwq0Nwq0Dwq0Lwq0Hwq0Pwp0AArUFwU6EAXqhwL1R4EGoEADUaCDUKCDUaBDUKBDUaDDUKDDUaAjUKAjUaCjUKBBKNBgFGgIClSMAg1FgYahQMNRoKNRoGNQoBEo0EgU6FgUaBQKNBoFOg4FGoMCHY8CnYACjUWBSlCgcShQKQp0Igo0HgU6CQU6GQU6BQWagAKdigKdhgKdjgJNRIHOQIE8KNCZKFAZClSOAnlRoEkoUAUKNBkF8qFAZ6FAU1CgShRoKgpUhQJVo0A1KNA0FKgWBapDgfwoUD0KNB0FOhsFmoECNaBAM1GgWSjQOSjQbBToXBRoDgpEc2GkAIx0How0D0aaDyMtgJHOh5EugJEuhJEugpEuhpEugZEWwkiXwkiXwUiXw0iNMFITjNQMIy2CkRbDSEtgpCtgpCthpKtgpKthpGtgpGthpOtgpOthpBtgpBthpJtgpJthpKUw0jIYaTmM1AIjtcJIK2CklTDSLTDSrTDSKhjpNhhpNYx0O4x0B4x0J4x0F4x0N4y0Bka6B0a6F0a6D0a6H0Z6AEZ6EEZ6CEZaCyOtg5EehpEegZEehZEeg5Eeh5GegJGehJGegpGehpGegZGehZGeg5Geh5FegJHWw0gEIzEY6UUY6SUY6WUY6RUY6VUY6TUY6XUY6Q0Y6U0Y6S0Y6W0Y6R0Y6V0Y6T0YaQOMtBFGeh9G+gBG+hBG2gQjfQQjbYaRPoaRPoGRPoWRPoORPoeRvoCRvoSRtsBIX8FIX8NI38BI38JI38FI38NIP8BIW2GkH2Gkn2Ckn2GkX2CkX2Gk32CkbTDS7zDSHzDSnzDSXzDS3ygSw1VgYrgaTAxXhYnh6jAxXCUmhqvFxHDVmBiuHhPDVWRiuJpMDFeVieHqMjFcZSaGq83EcNWZGK4+E8NVaGK4Gk0MV6WJ4eo0MVylJoar1cRw1ZoYrl4Tw1VsYriaTQxXtYnh6jYxXOUmhqvdxHDVmxiufhPDVXBiuBpODFfFieHqODFcJSeGq+XEcNWcGK6eE8NVdGK4mk4MV9WJ4eo6MVxlJ4ar7cRw1Z0Yrr4Tw1V4YrgaTwxX5Ynh6jwxXKUnhqv1xHDVnhiu3hPDVXxiuJpPDFf1ieHqPjFc5SeGq/3EcNWfWDT1nwKtJb6qikpvtMgoKkE1LmqM/N9p4jfED46LdzgTEpOSU1LT0jt17tK1W/cePTMyXe6s7JzcvF3yCwqLeu26W+8+u++x515777Pvfvsf0PfAfv0HDDzo4EMOPezwI448atDgIcVDhw0/+pgRI48dNfq4McefMLZkXOmJ4086+ZQJp552+sQzPGeWlXsnVUz2nTWlcmpVdc202jp//fSzZzTMnHXO7HPn0FwK0Hk0j+bTAjqfLqAL6SK6mC6hhXQpXUaXUyM1UTMtosW0hK6gK+kqupquoWvpOrqebqAb6Sa6mZbSMlpOLdRKK2gl3UK30iq6jVbT7XQH3Ul30d20hu6he+k+up8eoAfpIVpL6+hheoQepcfocXqCnqSn6Gl6hp6l5+h5eoHWExGjF+klepleoVfpNXqd3qA36S16m96hd+k92kAb6X36gD6kTfQRbaaP6RP6lD6jz+kL+pK20Ff0NX1D39J39D39QFvpR/qJfqZf6Ff6jbbR7/QH/Ul/0d/8VpLfJvJbQH57x2/d+G0Zv+Xit1P8VonfBvFbHH77wm9N+G0Hv6Xgtwv8VoBn8zwL59kzz3p5tsqzTJ4d8qyOZ2M8i+LZD89aeLbBswR+uuencn6a5qdgfnrlp05+WuSnPH4646cqfhripxh++uCnBr7b812a7658V+S7Gd+F+O7Boz6P1jzK8ujIoxqPRjyK8NXPVy1fbXyV8NnNZ2NjI5+3ppL5G5znB1qKq6vq/IsCrUN9/Ld+R2DFiCq/t8Jbu6y0X+RtLt7YP95W/8ACY/84W/3jFwSWt5X6b2KOihBp5VhvpcfPHy/BHmuwmZBobzTiAre1WVPu8XuKq2saQg81VLRJgHPbhUcvCQuiVsOnSsNC8FNLS/saPjQ+LIRRA/sbPlURFhQKfWFBrnBKWFAonBUWFApnhwW5wjlhQaGQLhckhUpqEiS5UhIlldplgqRS2yJICrUrBEml9n5BUql9UJAUatcKkkrtekFSqWWCpFD7kiCp1H4gSCq1mwRJoXazIKnUbhUkldqfBEmh9hdBUqjl240oKhTzLUkU5ar5riWKSuW5oqhUvosoqpQXiKJS+f6iqFTeVxRVyvuJolJ5sSgqlQ8TRZXyo0VRqXy8KCqVnyyKKuUTRFGpfIooKpVPFUWV8mpRVCqfI4pK5QFRVCmfJ4pK5fNFsZ1y0wnB5nlpaIfPGGcElo2unt4snihCRy8TO8ke2xNYNcRX5alt4J3G1CwJgZcNLi/f/vghTYKG1SOqyrf/tmPHL36UbK88rCKk3vzMDuNopIiuMbSlimabxirdnrldjfQ0hR862WN3s++HTnI/pIH80MnshzSjH3b86BQd0q4lQTS5XUui6Irgqd4XaCnxV9d6rb2YBvCi5GFTzA+bImqRdEs1d0sNj9HyUdWecuFRkkW46kGTbZkZ0qeN1Eb+Xxipg7UO1jpYayO1kTpY62Ctg7VevdpIbaQO1jpY62CtQ4w2UgdrHax1sNbBWhupjdTBWgdrHaz16tVGaiN1sNbBWgdrHWK0kTpY62Ctg7UO1tpIbaQO1jpY62CtV682Uhupg7UO1jpYayO1kTpY62Ctg7VevdpIbaQO1jpY62CtV682UgdrHax1sNbBWhupjdTBWgdrHaz16tVGaiN1sNbBWgdrHWK0kTpY62Ctg7UO1tpIbeS/aKQh1DrCYoKxzRns1VbePBhG/B2tbR6/wExw2v37Kcv5aNY0WT+H0/i3Yopbhvu8leUcu7HsgOoLlnh/WznhhMYZCyezUbeWJH312oBtLZM3P79u3Q+tY73++toq6y0j2bhlOMPhtl30TQl/oN3vU8OBe/nI+qk1fDCnBefMjpakMCM4X4ydk6ytSzFaJ50nQaCxQ2qEDmkrR3nr6sZN9lRZqkkOtLY91IhJIZPTmGNqaESH84fxVVS1TaIlaz0z/d6yifX+yokVXn+p31fp8zdwl/m9M/wb4tyB1aO9U6trG7h9tVyjuExkLSnSllRpS5q0JV3a0kna0lna0kXa0lXa0k3a0l3a0kPa0lPakiFtyZS2uKQtcs9lSVuypS050pZcaUuetGWXtonVWuKbWlPp/Scc/K/91P4PTET6yMD+tpjLS/seeLD6t5EtbWw0R/bkUOyNFNINm0+iIgdIsbdddLefA6TIc4BEUA5gsbcnKnKq1I7lPerTwUpjiiFESaEtuG0FzKeZtChOM2nKrEfSKb39tmOlMDW89YS7McecDk+cOJUblpb2jcL5LR1MIbt1OC9L6nAObfEUne0RLOZzF3sEp5nQ1R4hwUzoZo+QaCZ0j/JoudXctYfd9NpE6GmP0NP8F4Hk6z7Jat03yxZphmSRJrRLJkyLNIM5rgrBl8jgDmWgbHeyfKd3+GhZ520L3f5aT5m/pKGqrNhTNtk7omq6p9LHN6pF8oNC4JZjvJ6awbW1ngYxv5AfyZIWGTbFln86N7X/dTfLjTx4QLYcnGuCWZezvAMjn2YNvz4Er5DCl42ur5RypTc3brPDHBHjvMvcyS0eVI3JtUsUozckQ4yCkm7ZsdifZe6ULT6K0f4sUYzJ/s6ybjmx2G/x0Dkq+7NFMSb7u8i65cZiv8VD56rszxHFmOyXXnjmxWK/xUPnqezPFcWY7O8GtT/Dpv0ZqsXtjm1xu4Xzs/GA6mr3MVNAzGGOdaGt6CHjbpgpnm6Dn3rcGvOoeaN2277eGlfrabveMicmboVpuYJpxhHNi2JE86xcGNWI5hmtyldkbwV2z462s7cCefaWD8reCsxjlS85lNzT7rqr2FNTV1/Jx1F+h2F5ACmIbzYdINr+eqX1YSN+seKAY2gJ3pLGcOuVvbijNxd2hlcwyDi9C0Rxx5/ptOqZt0Pt6n/Ubv9hTM1icQ3wI49lVzO3QHSa1d8etcTssMD4kTzZHJXbun2Qwj92FwmG9ZijWI82l0SG/fWYL1+POaD1mG91fJHfphTaTZ0kagvNagsVbigS24LBeqM5tBaJ+41EdZFZdVHEXbqXJF0oEu03b2u9mOM905rLj2JLyVeGSdWWkv9f12fwlXAGMWXHuWJb0I+fS42SDLqgoYfFoOcz53Eh+BZTwBBsz1IHU7dEv/AUPS30u5njWyFHlL2VkGP8ui3BbjwJ6jjL7ILQN2zRZ13uiIvAYpJkiaNimibRzDyXMv+Q5ppZtwd9M2xavaeyTkpwWXgoizm2hUZvtlSFxP0utfs5/M8o3O/eee7Piuj+HCtPxpBp5YijYnK/4AU7qa4rCvfnKN0fMWdxpkR2vyty9LFyv4s506Nwf9bOc78rFve7Ouh+t9L9mTJopvL2KsbV7xYVWy1Qp0twv3F/EG/P1PuD7A4xUz1DMpgzJ4oZ4tp5MyQjlv0hI5arpCxxVEwzpN38iX5/yIxihriVMyRTvT+4mbN35ACR2Roh9lg5P5M59wih59pYFhmRs+S6UJbc2Ggjjw21FFhn0Jk9Y81jrXPsntGlsuqLManjM5WOz2s3oFbe2U8RGjLNoUG2sizyRddOv79xyfPFDFC+6FLOTHkqYHE8cMe2P+y8hRC60LFeBvHYZRAf5TKQbDLCF43WX1Q5DwvN5HnSTSaxg5tM945sMpmxbDLq/SBJmatm27AkKYpY41LGmiT1MYQfFIdHcQo1W5bQ4e0vIeL2N1KwTP7tt8v88pHgSfk345mRvxkvjOWImq+8VXKrbkbypYbEdglQyJzj/t1LgMKI66/Iargi3oRZXZ8Jo2Jaf72iGOT82C4BiqK9BMi38FARc06MvP6KIiQo8h2vyHyXLAyz/GIsX7gYM27noS1ffGFRPkk6P/3AmE2/1vQxfy8W9HLwNYoOKvo45fhhjnsXFkRWJHlv2yl5d1w8Yhv7OExvTicz5yzj/+gJWRLtaSq0EKN7/dsZ7tBOc5rkbfb0sGk7/Ow82zAqKWGG4W329PBHrN81N1qXFuHl9HRjh/QIHTpZvs2eJrwMb/BJJ+ask00v26+EBkfsHImXnaD5/HLylh/XP1PRuNMXzvziJ/f96LM1M3e6ojUD9jm080l95kZU9B9brTyt/PcAAA==",
2293
- "debug_symbols": "tZnRbhs5DEX/xc95kEhKlPIrQVG4qVMYMJzATRZYBPn3JTO6sr2AVNduX6KTxHNMcShKY7+vvm++vf34ut0/Pf9c3T+8r74dtrvd9sfX3fPj+nX7vLe/vq+C/8hUVvd8Z2Nd3WcbObQxtpHayG2UNqY25jZqG0sbm0+aT5pPmi/Z69TGbH+vPlIbzR+jQwLYO0QPMSugAGoDDYAIIAADBJAAMCvMCrPCXGAuMBeYC8wF5gJzgbnAXGAuMFeYK8wV5gpzhbk2swa/KjlEAAH8NdkhAxRg707BoTaIARABBGCAvTv55TEBMkABblaH2oACwM3VwczswRMDBJAAGaCAAqgNvDYXiACYGWaG2QuUPS1eoQsowM3FoTbwKl3ALhefu9iLhRzsxSIOtUEKAAtDXJgIwAABJEAGKMDNnsNUG+QAiAA3ew4zAwRg5uSh+gJZQAEFUBv4AlkgAsycogMDBJAAbvZk+gJZoADc7EnwBbJABBCAAQJIADd7EnyBLFAAtYEvkORJ8AWS/O74AlmAAW72bPgCWSADFFAAdYHii2gB70rBgQAMEIB3OnLIAAV4s2OH2sCXVRaHCCAAA9xcHMys/ha+rBZQQAHUBr6sFogAM2t0YICZ1cPwZbVABrjZ392X1QK1gS+rBSKAAAxwc3JIgAxQgJuzQ23gy2qBCPCr1EEBBWBXFZ+Xr68FIsDiKT5BX18LCCABMkABBeBmv1++vhaIAAL4TMvHx90Km+TX18Nm43vkya5pe+nL+rDZv67u92+73d3qn/Xu7fNFP1/W+8/xdX2w/1rUm/13G034tN1tnD7ujleH8aUx2KbbLjfOtStiOJfEsUS8OX8qRLQL9Px6Gl/PCTNgy0oPQOtvzKKWPgtrX8NZyFiSUqnNkXLIR0XiM0UaKygTkkl2+OiKfHEMWXOPodIwhonCDlPcFHZOCkNFGStsT28GPRWoXjwN7TEk23WHMcTJPWWKuB1MnAa5nBtqrysOZWSYFKZEgkEi1yvup20nSIT17XEiJo7q561PRaXjJCReHEPtk0i1hqtqKgQocohjRdTJGq0ZVRWrSnek81UeJ3UZNfZeZaeEoaLOkokgajltNflyQ5XeaWIaKmjSL4kEDqI0vKdEs45Hx7ad4jgMntxVaxW4q/aYcxIGnTtmlVEiGq89q9SxY9Y1JfWmebypEq4sjDouDJ3dk54Muz08UtAkipwSOlZOVa6KImZFFNbHRwqedD1JfTPWcV3wbDuPpSsoysk9Pd9LeVafqd+QxCcGvjwKYuwhwiGOo5hUZ6QCR+QYx3FMHKwZDraz6jiOPKvP0M8WVqtnszlfJzwpDpa+IaY6nsvlcVAYx1FnvUfCsflI4LFlGgtL7LFw0qFFJlXC+Xh0lGFOpoaLsiqTPiqlt3OxJ4PxPCYOYsyDEl0VBZXeRUu+qjourXSZ1Kh99Nb3FFvB41yUP5DPcnM+y9/M56W5SHR7LmaOy3IxNdycCwte+zw0XNUxLs6F/l3HhfnUm/M52x25Px0JT9Zqjn9gd5ydNrQ/M0sYn6en2eynDZJw3alJYj9Pp5PD8P8UOd16asqz7lkDVjtXomFl5Vl1BsVp2o6/8UpHTt2h410111srfJrPi+pi9mBBqT9YUB4/OeukbdlXLbir9h0LDx7fp4ZC2h9vpF5l0OMDkl7xEYJ9WdafKjiMn71/cWKLx8/H5OQTmd88951aZFzjWm7fFbXe3sX15hqfGsZd/Iv9un7cHs6+BP1w1WG7/rbbtF+f3vaPJ/99/fcF/8GXqC+H58fN97fDxk3Hb1Ltx0Oxz8pLpS93K/s0+SFbg8yk9pt/GfBQrGisIX358Fj+Aw=="
2293
+ "debug_symbols": "tZndbhs5DEbfxde5EEn9Ma8SFIWbOoUBwwncZIFFkHdfMqNPtreQ4NrtTXXSeI4pDkVpMu+r75tvbz++bvdPzz9X9w/vq2+H7W63/fF19/y4ft0+7+1/31fB/8lcV/dyZ6Ou7rONEtpIbeQ2ShtjG1MbcxtLG2sbmy82X2y+2HzJPldszPb/6iO30fxEDglg30AeYi6ACtAGJQAIwAABREACwFxgLjAXmCvMFeYKc4W5wlxhrjBXmCvMFWaFWWFWmBVmhVmbuQS/KjkQgAH+meyQAQVg387BQRtQABCAAQKwb2e/nBIgAwrAzcVBG3AAuFkdzCwePAsgAhIgAwqgArSB1+YCBIBZYBaYvUDF0+IVukABuLk6aAOv0gXs8uhzj/bhyA724RgdtEEKAAsjujAxQAARkAAZUABu9hwmbZADgABu9hxmAUSAmZOH6gtkgQKoAG3gC2QBApg5kYMAIiAB3OzJ9AWyQAW42ZPgC2QBAjBAABGQAG72JPgCWaACtIEvkORJ8AWS/O74AllAAG72bPgCWSADCqACdIHqi2gB70rBgQECiADvdOyQAQXgzU4ctIEvqxwdCMAAAbi5Opi5+Ff4slqgACpAG/iyWoAAZi7kIAAzFw/Dl9UCGeBm/3ZfVgtoA19WCxCAAQJwc3JIgAwoADdnB23gy2oBAvhVxaEAKsCuqj4vX18LEMDiqT5BX18LREACZEABVICb/X75+lqAAAzwmdaPj7sVNsmvr4fNxvfIk13T9tKX9WGzf13d7992u7vVP+vd2+eHfr6s95/j6/pgv7WoN/vvNprwabvbOH3cHa8O40sp2KbbLjfO2hUUziU0lkRvzp+KGEsXlPPreXy9JMxALCs9gKK/MQutfRbWvoaziGNJSlWbI+WQj4okZ4o0VnBmJJPt8NEV+eIYcsk9BuVhDBOFHaakKeycFIaKOlbYnt4M5VRQysXTKD2GZLvuMAaa3FNhwu0QljTI5dygva4k1JFhUpiRGIZIolfcT9tOkAjr2+NETBzq561PhfJxEpEujkH7JJJquKqmQoAiBxorqEzWqGZUFWmJ3ZHOVzlN6pIK9V5lp4ShQmfJRBBaT1tNvtygsXcaSkMFT/olc4SDOQ3vKfOs4/GxbScahyGTwqjdkWzbOgmDzx3zytBeGRzGjlnXjKk3zeNNjeHKwtBxYZTZPRHq9yTKSMGTKHJKPRdJ41VRUC6Iwvr4SCGTrhdT34zLuC5ktp1T7QqmeHJPz/dSmdVn6jckyYlBLo+CBXtIlEDjKCbVSVzhICEaxzFxSMlwiJ1Vx3HkSRyZYs9HphSH60QmxSGxb4hnq1WujaPIOI5ZB0yKjOhpnf/imEYixz6aI407R5zUiOTjwTEOMzI1XJTTOOmiMQjaVwwnx99f5jFxsGAenPiqKLj2HlrzVbVxaZ3HMju+hr6jZBpXRqx/IJ/15nzWv5nPS3OR+PZczByX5WJquDkXFnzt88h0Vce4OBfl7zouzGe5OZ+zvVH6s1GUyVrN9Af2xtlZo/Qn5hjGp+lpNvtZg+2WXHVmitRP0+nkKPw/RU63npnyrHsGxWq3ZI731Tzb3zkfn3grX+noUzFdHTv01gqf5vOiupg9VnBCw8icx8/NZdK27EULUmFvWGTw8D41VMZp3F676FWG0udRyxV/QLBXZf2ZQsL4yXt6Xsv9GU0z5evOfKcOGdd3qbfviEVv7+Dl5vqeGsYd/Iv9uH7cHs5ef3646rBdf9tt2o9Pb/vHk9++/vuC3+D16cvh+XHz/e2wcdPxHar981Dtr+RV+cvdyv6O/GDn+LvMxX7y1wAP1QpGA3358Fj+Aw=="
2294
2294
  },
2295
2295
  {
2296
2296
  "name": "public_dispatch",
@@ -2314,7 +2314,7 @@
2314
2314
  "error_kind": "string",
2315
2315
  "string": "rejecting all"
2316
2316
  },
2317
- "9663057235827813545": {
2317
+ "11194752367584870169": {
2318
2318
  "error_kind": "fmtstring",
2319
2319
  "length": 27,
2320
2320
  "item_types": [
@@ -2345,8 +2345,8 @@
2345
2345
  }
2346
2346
  }
2347
2347
  },
2348
- "bytecode": "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",
2349
- "debug_symbols": "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"
2348
+ "bytecode": "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",
2349
+ "debug_symbols": "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"
2350
2350
  },
2351
2351
  {
2352
2352
  "name": "sync_state",
@@ -2375,11 +2375,6 @@
2375
2375
  ],
2376
2376
  "return_type": null,
2377
2377
  "error_types": {
2378
- "291858071673084052": {
2379
- "error_kind": "fmtstring",
2380
- "length": 40,
2381
- "item_types": []
2382
- },
2383
2378
  "361444214588792908": {
2384
2379
  "error_kind": "string",
2385
2380
  "string": "attempt to multiply with overflow"
@@ -2388,11 +2383,7 @@
2388
2383
  "error_kind": "string",
2389
2384
  "string": "Attempted to read past end of BoundedVec"
2390
2385
  },
2391
- "1998584279744703196": {
2392
- "error_kind": "string",
2393
- "string": "attempt to subtract with overflow"
2394
- },
2395
- "2767104006428505934": {
2386
+ "1064022259863234536": {
2396
2387
  "error_kind": "fmtstring",
2397
2388
  "length": 101,
2398
2389
  "item_types": [
@@ -2403,15 +2394,26 @@
2403
2394
  }
2404
2395
  ]
2405
2396
  },
2406
- "3632530479893888919": {
2407
- "error_kind": "fmtstring",
2408
- "length": 98,
2409
- "item_types": []
2397
+ "1998584279744703196": {
2398
+ "error_kind": "string",
2399
+ "string": "attempt to subtract with overflow"
2410
2400
  },
2411
2401
  "5421095327929394772": {
2412
2402
  "error_kind": "string",
2413
2403
  "string": "attempt to bit-shift with overflow"
2414
2404
  },
2405
+ "5449178635769758673": {
2406
+ "error_kind": "fmtstring",
2407
+ "length": 61,
2408
+ "item_types": [
2409
+ {
2410
+ "kind": "field"
2411
+ },
2412
+ {
2413
+ "kind": "field"
2414
+ }
2415
+ ]
2416
+ },
2415
2417
  "9530675838293881722": {
2416
2418
  "error_kind": "string",
2417
2419
  "string": "Writer did not write all data"
@@ -2432,27 +2434,20 @@
2432
2434
  "error_kind": "string",
2433
2435
  "string": "extend_from_bounded_vec out of bounds"
2434
2436
  },
2437
+ "10835969307644359280": {
2438
+ "error_kind": "fmtstring",
2439
+ "length": 40,
2440
+ "item_types": []
2441
+ },
2435
2442
  "11021520179822076911": {
2436
2443
  "error_kind": "string",
2437
2444
  "string": "Attempted to delete past the length of a CapsuleArray"
2438
2445
  },
2439
- "11127167352969888584": {
2440
- "error_kind": "fmtstring",
2441
- "length": 61,
2442
- "item_types": [
2443
- {
2444
- "kind": "field"
2445
- },
2446
- {
2447
- "kind": "field"
2448
- }
2449
- ]
2450
- },
2451
2446
  "12469291177396340830": {
2452
2447
  "error_kind": "string",
2453
2448
  "string": "call to assert_max_bit_size"
2454
2449
  },
2455
- "12643885028103362594": {
2450
+ "12820178569648940736": {
2456
2451
  "error_kind": "fmtstring",
2457
2452
  "length": 48,
2458
2453
  "item_types": [
@@ -2476,14 +2471,19 @@
2476
2471
  "error_kind": "string",
2477
2472
  "string": "Index out of bounds"
2478
2473
  },
2474
+ "17110599087403377004": {
2475
+ "error_kind": "fmtstring",
2476
+ "length": 98,
2477
+ "item_types": []
2478
+ },
2479
2479
  "17655676068928457687": {
2480
2480
  "error_kind": "string",
2481
2481
  "string": "Reader did not read all data"
2482
2482
  }
2483
2483
  }
2484
2484
  },
2485
- "bytecode": "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",
2486
- "debug_symbols": "vf3bjuVMcmYBvktd64JuBz/oVRqNhlqtbhRQkBpqaYCBoHef7UbSl2X+Cg9G7PjnpnJVVaYtbift48lJ/sdf/tc//c9//z//46///L//5f/95e//23/85X/+61//9re//p//8bd/+cd/+Le//ss/v/7X//jLMf9jtL/8vf7dX0b/y9/7648Rf5TjuP4s159y/anXn3b96def9fqzXX/268+rXrnqlateueqVq1656pWrXrnqlateueqVq55c9eSqJ1c9uerJVU+uenLVk6ueXPXkqqdXPb3q6VVPr3p61dOrnl719KqnVz296tlVz656dtWzq55d9eyqZ1c9u+rZVc+uen7V86ueX/X8qudXPb/q+VXPr3p+1fOrXr3q1ateverVq1696tWrXr3q1ateverVq1676rWrXrvqtateu+q1q1676rWrXrvqtatev+r1q16/6vWrXr/q9atev+r1q16/6vVXvfb6cxzXn+X6U64/X/VKmWA3+A2vkkUnvGqW+nd/kdkMpU14/WU5Jrz+ssiE118Wn9Bu6DeMC2YPnFBueC2Flgl6g93gN7wq61TMVjihXzA3etUJ8y/PgnMz17mEczvXPqHfMC6Ym/oJr8WwqZgbsc2Cc6u1WWdurjZ/cmyf85fGBhrQbug3jAtiIw2Ya23+89hMA/QGu2FWnosam2rArDwXLDbWgHFBbK4B5Qa5QW94Va7TPrfZE+oN7YZ+w7hgbrgnlBvkBr3hrtzuyu2u3O7K7a7c7sr9rtzvyv2u3O/K/a7c78r9rtzvyv2u3O/K46487srjrjzuyuOuPO7K46487srjrjyuynocN5Qb5Aa9wW7wG+oN7YZ+w1253JXLXbnclctdudyVy1253JXLXbnclctdWe7KcleWu7LcleWuLHdluSvLXVnuynJX1ruy3pX1rqx3Zb0r611Z78p6V9a78tw7VHvBbLQTyg2zcp+gN9gNfkO9od3wqtzin48LZg+eUG6YUecT9Aa7Yf7zVzPqbKs2C8626nNRZ1t1mfD6y33+5dlWJ9Qb2g39hnHBbKtRJpQb5Aa94VV5TMVsqxPqDa/KQyf0G8YFs61OmJXnws8mGm3CDOpjLv3smYvGTbNrXscxk2aOH3NsIv6PucCR/yf5orooKk/H6IvGRXYci8oiWRS7GJlki2Ino5NmvRJ/b9w0e+WiskgW6SJb5IvqorZoOcpyyHJIOMYkWTQdcw9ns3Mu8ptmX7yOvCbF35u/SG2RL6qL5rLI/L2zFy4aN9mxaC7L3DXa7IeLdJEtCsdcequL2qK+aNzkx6Jw9EmySBfZojWmvsbU15j6GlNfY1rXmNa13upab3Wtt7rWW12Ouhx1OWr8jrk+6ripHYvKorXemi6yRb6oLmqL+r1W27ipH4vsXtPRW7Euo7dOGjdFb51U7nU5ZJEuskV+r8vospPaor7oXoN+HIvKonsN+qGLbJHfFD2jx6RZbx40eXTASWWRLNJFtmjWU5tUF7VFfVE4XtHk0SknlUXhmEsf3XOSLfJFdVFb1BeFY/626J6TyiJZFJVfI+nRATEGsT3HL4rt+aS+aI1QXSNU1wjF9hy/Mrbnk2zRGqHYnuP3xvZ8Ul807t8R2/NJZdEaobZGqK0RamuEYnuOXxnb80l90RqhXu4xiK3Y5hjEVnzSuCm24pPKIlmki2yRL6qLlmMsx7gd9TgWlUWySBfZIl9UF7VFfdFylOUoy1GWIzpgHu7X6ICTyqL4e22SLrJFvqguaovmsrhOGjdFB5xUFk2H2yRdZIumw31SXdQWhWPaogPmkX+NDpgHWDU64CRZpItskS+ajlomtUV90bgpuuekskgW6SJb5IuWw5fDl8OXI/qtzhGKfjtJFoVjjlD020m+qC5qi/qicVP01kmrXlv1ordqnVQXtUV90bgp9hUnlUWySBfZouXoy9GXoy9HX46xHGM5xnKM5RjLMZZjLMdYjrEc43a041hUFskiXWSLfFFd1Bb1RctRlqMsR1mOshxlOcpylOUoy1GWoyyHLIcshyyHLIcshyyHLIcshyyHLIcuhy6HLocuhy6HLocuhy6HLocuhy2HLYcthy2HLYcthy2HLYcthy2HL4cvhy+HL4cvhy+HL4cvhy+HL0ddjrocdTnqctTlqMtRl6MuR12OuhxtOdpytOVoy9GWY/V5W33eVp+31edt9Xlbfd5Wn7fV5231eVt93laft9XnbfV5W33eVp+31edt9Xlbfd5Wn7fV5231eVt93laft9XnbfV5X33eV5/31ed99Xlffd5Xn/fV5331eT/7fEwaN519HhSVfZIuskWzciuT6qK2qC8aN0V3n1QWySJdZIuWQ5ZDlkOWQ5ZDl0OXQ5dDl0OXQ5dDl0OXQ5dDl8OWw5bDlsOWw5bDlsOWw5bDlsOWw5fDl8OXw5fDl8OXw5fDl8OXw5ejLkddjrocdTnqctTlqMtRl6MuR12OthxtOdpytOVoy9GWoy1HW462HG05+nL05ejL0ZejL0dfjr4cfTn6cvTlGMsxlmMsx1iOsRxjOcZyjOUYyzFuxziORWWRLNJFtsgX1UVtUV+0HGU5ynKU5SjLUZZj9flYfT5Wn4/V52P1+Vh9Plafj9XnY/X5WH0+Vp+P1edj9flYfT5Wn4/V52P1+Vh9Plafj9XnY/X5WH0+Vp+P1edj9fk4+9wnlUWyKBxtki3yReEYk9qivmg6+nREn58Ujj5JFumi6ZiXNEf0+Ul1UVvUF42bos9PKotkkS5ajrocdTmiz+fl0RF9ftK4Kfr8pLJIFukiW+SL6qLlaMvRlqMvR1+Ovhx9Ofpy9OXoy9GXI/q8z7UVfR4UfX5SWRT15lqI/h3HpL5oXPS6UHuA81/PC8UvFFBBA6OWxA3rkGqggAoa6GAFYxFP7OBYGN15YQEFVNBAByuILbp0WNxmj7oeKKCCBjpYwQZ2cCyM3rwwbC1QQAUNdLCCDezgWBhdeiE2x+bYHJtjc2yOzbE5toqtYqvYKraKrWKr2Cq2iq1ia9gatoatYWvYGraGrWFr2Bq2jq1j69g6to6tY+vYOraOrWMb2Aa2gW1gG9gGtoFtYBvYxrKV4wALKKCCBjpYwQZ2EFvBVrAVbAVbwVawFWwFW8FWsAk2wSbYBJtgE2yCTbAJNsGm2BSbYlNsik2xKTbFptgUm2EjSwpZUsiSQpYUsqSQJYUsKWRJIUsKWVLIkkKWFLKkkCWFLClkSSFLCllSyJJClhSypJAlhSwpZEkhSwpZUsiSmEIjRwkcC2eW3DiniZQjUCZKoIIGOljBBnZwLJxZcmMBsXVsHVvH1rF1bCPqamBUiF88DHSwgg3s4FzeedPo1UIHWEABp00s0EAHp23eWSrnVJ0LOxi2OjEm7FxYQAHD1gKjbg9sYAfHwpkEMu/EvHDWnfN8SszmkTmv54UKGujgtGn84pkEN3ZwLNSwxW/TUMTyaihicWb7i8XizPYXO/9uBRvYwbFwtv+NBZw2i4Ga7X9juzeNmEF041joB1hAARU00MEKYnNsHoseP74eYAEFVNBAByvYwA5ia9gatoatYYvuPk50sIIx1SzWW3T3hWNhdLfHBhPdfaGAChroYAUb2MGxcGAb2Aa2gW1gG9gGtoFtYBvLFjOVbiyggAoa6GAFG9hBbAVbwVawFWwFW8FWsBVsBVvkw7w9VmJG043TdpwY+xYLdLCCDezgWHgeE5xYQAEVxKbYFJtiU2yKzbAZNsNm2AybYTNshs2wGTbH5tgcm2NzbI7NsTk2x+bYKraKrWKr2Cq2iq1iq9gqtoqtYWvYGraGrWFr2Bq2hq1ha9g6to6tY+vYOraOrWPr2Dq2jm1gG9gGtoFtYBvYBraBbWAby3bO1LqwgAIqaKCDFWxgB7EVbAVbwVawFWwFW8FWsBVsBZtgE2yCTbCRJUaWGFliZImRJUaWGFliZImRJUaWGFliZImRJUaWGFliZImRJUaWGFliZImRJUaWGFliZImRJUaWGFliZImRJUaWGFliZImRJUaWGFliZImRJUaWGFliZImRJUaWGFliZImRJUaWGFliZImRJUaWGFliZImRJUaWGFliZImRJUaWGFliZImRJUaWGFliZImRJUaWGFliZImRJUaWGFliZImRJUaWGFliZImTJU6WOFniZImTJU6WOFniZImTJU6WOFniZImTJU6WOFniZImTJU6WOFniZImTJU6WOFniZImTJU6WxAw58fNRlQZ2cCyMM5QLCyigggY6iE2xKTbFZtgMm2EzbIbNsFnYamADOzgWxtnMnKX0wgIKqKCBDoatBTawg2EbE+Ns5sICCqiggQ7WhXGyMicmlZibd6OAChro4CxWJbCBHRwL42TlwgIKqGAUi/GNc5ELx8I4F7mwgALOYi2KxbnIhQ5WcNqaBnZw3Bhz+mTOtS8xqe9GAcNWA8PWAsM2AivYwA6OhXEucuG0zen6Jeb33aiggQ5WsIEdHAvjXORCbIJNsAm2uFYxb3qVmCl4YwPD1gPHwkiCCwsooIIGOljBBmJTbIYtkiDuO8XMwRsVNNDBCjZw2uLGVEwgvDCSIC79xRTCGwVU0EAHK9jADoYtflAkwYVhiw0mkuBCBQ181dUjfsU8frhxLJyhcGOZGGtzhsKNChroYAXDFoveOjgW9gMsoIAKGuhgBbF1bB3bCFuMwyjgtMVl2JhqeKOBs0I8MhgzBjUugcaUwRsNdHAuWVyPimmDN3ZwLJw9/7qaEFhAARUMWw90sIIN7OBYKGEbgQUUUMFpk/jx8RTihRVsYAfHwnge8cICCqggNsWm2DRsMWbawbHQDjBsFiigggY6WMGwnc+3dnAs9ChWA+OftcAGdnAsrLGQsS5qAQVUcC5kXEyOmYM3VrCBrO7K6o6WvpDV3VjdjdUdLX1h2GJTjpa+sIHTpjFQ0dInRktfOG16Pv4roIIGOljBBnZwLIyWvhDbwDawjag7V1bMCHxdywpU0EAHK9jAuThxUT0mBl4YfXxhAadtzr4vMU3wRgOnzTSwgg3s4FgYfXxhAcNmgQoa6GAoZmfFxD+NC/sxj0/jInVM5LuxgAIqaGAoYqCinS5sYAenzWMZ5i70xgJOW1xEjVl9NxroYAUb2MGwxUBFF15YQAFDEasweshjzKKHLhRQwfhnsZ1FD11YwQZ2cCyMHopD7Jivd+O0xQFyzM7Tev7dCs66NVZAdMuFY2F0y4UFFFBBAx2sILaBbSxbTNZ7XdsMLOC0zcljJebr3WjgrBBH5jHtTuMYPObd3Wigg3PJ4nA85t7d2MGxMBonjtdj/t2NAipo9/jGHLwbK9jADo6FsQOMU4KYiXejgArGQsbwRQ/1GJLooQsb2MGxMHrowmmLw/GYMHejggaGLUYneujCBobNA8fC6KELCyigggaGLUYn9mQXNrAvjNbr54sa4u/G6EQPXdjBsTB66MICCqiggQ5i69g6tuiLOCUY0RcXNnD+3bheEnPgAiXmwN1YQAEVfC2ZzcPxFzpYwQb2iSVwLJy7pBvLRAkUUMGwhbiEzQPD1gIb2MGxUA6wgGHrgQoa6GAFG9jBsVAPsIDYFJtim4eWVmLM5qHljQ2cthJjNhvywnh7xoUFnLYSw2dRtwZWsIEdHAv9AGfd84Ujs2NvVNDAaZtHuhJT525s4LRJrM3ZsRfOjr0xbLGOq4AKGhi2WMgadWPF1rGwHWABo+4InHU1xnfuIS3efhKT5G6sYAOnLV6HEpPkLpzdfWMBp03jt/VQxPL2UMTi9FDE4syWNjv/bgfHwrmzvLGAAio4bfFmlZgZd2JMcbP55KTEFLcbFZz/bB7kSExxu7GCDezgWBjdfWEBBVQQW8FWsEV3z0MfiSluN46F0d3xdpeY4najgFGsB85/Fm8fiblqNg9cJOaq3SjgXMgaimjTCx2sYAM7OBZGm86nHSXmqt0ooIJhi3URzXthBcMWPyia98KxMJr3wgIKqGDYRqCDFWxg2GIziuY9MZr3wmlrsd6ieS9UcNZtMSTRpi3+WbRpi98WbXqhgFEhljfa9EIHK9jADo6F0aYtflC06YUCKsi66KyLzrrorIvOuuisi8G6GKyLwboYrIvBuhisi8G6GKyLuRu3HoM6d+Mnxly1G6dtHkdJzFW7cdbt8f6maOkLGxh1a+BYGC19YdRtgQIqaKCDFWxg2HrgWBgtfWEBw2aBUWEEdnAsjO4e8Yujuy8UcC7viF8c3X2hgxVsYAfHwujuODaKqWg3Cqhg2I7AqBC/LTr2wgIKqKCBPl9+FXXjjVYXNrCDY+Lst/PNVhcWUCbGOo73W11oYNhCHK9mO2Ko4+1scdgR889uHAvjNW0XFlDAaYujlZh/dqODFWxgB8fCeInbhQUUEFvH1rHFa91KjFm82e3CDoYtfvw4wAIKqKCBDk5bvNct5p/dOG0SoxNvRwyM+Wc3FnDWjcOvmGl2YwUbGHUtcCyMFyVeWEABFQzbCHSwgg3s4FgYr1G8sIACKohNsAm2eLdiHJTF/LMbpy0Ov2L+2Y0FnBXiNXYxe8zj+Cxmj91YQAHnksVL72L22I0OVjCWrAV2cCyMN9ddOG3zupzE7LEbFTTQwQpO2/livej5C8fC6PkLwxY/Pnr+QgUNdLCCDezgWBg9fyG2hq1hi56Pg9OYPXZjBRsYtho4FkbPX1hAARUMW4x69PyFdWG09LxiKDENzC22s2jeCx2s4FzIeBFhTAO7cdwY08BunAs5L/1JTAO7UUED1+qOaWA3NnCt7pgGdmE5wAKGzQIVNHDa4rA5Jnx5HDbHhK8Lo3kvnHXjYDomfN0YdVuggQ5WsIEdHAujeeNwPCZ83SigggY6WMEGdnAsNGyGzbAZNsNm2AybYTNshs2xOTbH5tgcm2NzbI7NsTm2iq1iq9gqtoqtYqvYKraKrWJr2Bq2hq1ha9gatoatYWvYGraOrWPr2Dq2jq1j69g6to6tYxvYBraBbWAb2Aa2gW1gG9jGssWErxsLKKCCBjpYwQZ2EFvBFqkxrxVLTPi6UcGwlUAHKxi2EdjBsTCyJM4LY8LXjQIqaKCDFWxgB8dCxabYFFukRosfH/kQp6kxievCyIcLCxgVPFBBAx2sYCxvjGTkw4VjYeTDhQUUUEEDHawgNsfm2CIU4mQ7Zm55nCrHzK0bDXSwgg0MRazjCIUTIxQuLKCAChoYe4ZYyOj5E6PnLyyggAoaOBc9zo89ev7CBnZwLIyev7CAAipoILaBbWAb2MayxdSuGwsooIIGOljBBnYQW8FWsBVsBVvBVrAVbAVbwVawCTbBJtgEm2ATbIJNsAk2wabYFJtiU2yKTbEpNsWm2BSbYTNshs2wGTbDZtgMm2EzbI7NsTk2x+bYHJtjc2yOzbFVbBVbxVaxVWwVW8VWsVVsFVvD1rBFVMx7dRITvm40MIrNRo+JWR7XgurZ8ydWsIEdHAuj5+NCTUzMulFABactLizFW+BurOC0xcWieBHcjePGeBXcjQUUUMGwWaCDFWxgKObwxcQsn+9ekJhh5XEJKWZY3aiggQ5WMBQjsINjYbTehWW+ijqW4XyX9YkK2kQJdLCCDezgWBjvtr4wbDFQ8X7rCxU0MBRzFZ5v/yr9ZEmsiS2xJ66JW+KeeCw+3wd2c0ksiTWxJfbENXFL3BMnb0nekrznG5rndE453/Z18/w7EuNzvvHrZk1siT1xTXwuWw3uiadX4iJgv97vfPK5bLEMKok18entwZ64Jm6Je+IBn++BvrgkPr0jWBNbYk9cE7fEPfGA/UhcEievJ68nryevJ68nryevJ29N3pq8NXnPd0DPmZ1yvhPs4vM90BeXxJJYE1tiT1wTt8TJ25K3J29P3p68PXl78vbk7cnbk7cn7/k+6HM7PN8IfTHb6vnGr5tLYkl8Lo8EW2JPXBOfXgvuiQdcGIfzPWA3S2JNbIk9cU18emtwTzxgORIzPucbvm5O45N6+XzP181pfDSNj6bx0TQ+msZH0/hoGh9N42NpfCyNj6XxsTQ+lsbH0vhYGh9L42NpfCyNj6fx8TQ+nsbH0/jUND41jU9N41PT+NQ0PjWNT03jU9P41DQ+NY1P6t+R+nek/h2pf0fq35H6d6T+HS2NT0vj09L49DQ+PY1PT+PT0/iMND4jjc9I4zPS+Iw0PiONz0jjM9L4jDQ+Y42PHscaHz2OklgSa2JL7Ilr4jU+ehw98YDLkXiNjx6lJx6wHIlLYkm8xkfP94Hd7Ilr4sY4SE+cxkfT+GgaH03jo2l8NI2PpvHRND6axkfT+GgaH0vjY2l8LI2PpfHxND6exsfT+HgaH0/j42l8PI2Pp/HxND6exqem8alpfGoan5rGp6bxqWl8ahqfmsanpvGpaXxaGp+Wxqel8WlpfHoan57Gp6fx6Wl8ehqfnsanp/HpaXx6Gp+exmek8RlpfEYan5HGZ6TxGWl8RhqfkcZnpPEZjE85jsRxnBPfgjlf7HWzJfbEcXwVH4g5X+51c0884PMYe5586fmCr5slsSY+j2NbsCeu8Hkm5IEN7GCcCcXfPc+ETiyggHEm1AMNdLCCYRuBHRwL/QALKKCCBjpYQWyOzbHNPqpzNqTGm65qbKkxp+jGBnZwVpjPNGnMNLqxgAIqGMViJcWHti4cC+NjWxdGsVgX8cGtCxU00MEKhi020fj41oVjYXyA68ICCqig3RjTgOp8p5XGNKA6n7nReGXVjQY6WMEGdnAsjM9sXVhAbPGxrTmxQWNy0I0OVrCBHRwL49NbFxZQQGyCTbAJNsEm2ASbYlNsik2xKTbFptgUm2JTbIbNsBk2w2bYDJthM2yGzbA5Nsfm2BybY3Nsjs2xOTbHVrFVbBVbxVaxVWwVW8VWsVVsDVvD1rA1bA1bw9awNWwNW8PWsXVsHVvH1rF1bB1bx9axdWwD28A2sA1sA9vANrANbAPbWLbz83wXFlBABQ10sIIN7CC2gq1gK9jIEiVLlCxRskTJEiVLlCxRskTJEiVLlCxRskTJEiVLlCxRskTJEiVLlCxRskTJEiVLlCxRskTJEiVLlCxRskTJEiVLlCxRskTJEiVLlCxRskTJEiVLlCxRskTJEiVLlCxRskTJEiVLlCxRskTJEiVLlCxRskTJEiVLlCxRskTJEiVLlCxRskTJEiVLlCxRskTJEiVLlCxRskTJEiVLlCxRskTJEiVLlCxRskTJEiVLlCxRskTJEiVLlCxRskTJEiVLlCwxssTIEiNLjCwxssTIEiNLjCwxssTIEiNLjCyxM0ssUEED4yhoBFawgWGrgWPhmSUnFlBABQ10sIINxCbYFJtiU2yKTbEpNsWm2BSbYjNshs2wGTbDZtgMm2EzbIbNsTk2x+bYHJtjc2yOzbE5toqtYqvYKraKrWKr2Cq2iq1ia9gatoatYWvYGraGrWFr2Bq2jq1j69g6to6tY+vYOraOrWMb2Aa2gW1gG9gGtoFtYBvYxrL5cYAFFDBsPdBAByvYwA6OhWeWnFhAAbEVbAVbwVawFWwFm2ATbIItOnY+t6YxK6nOWc0as5JuFFBBAx2sYAM7OBY6Nsfm2Jwli367cCyMfptTrzUmHd0ooIIGOljBBnZwLIx+mxOyNSYd3Ri2FqgLo1ssFjK65UIBFTTQwQo2sINj4cA2sA1s0QwWvyKaYT7VpzFlqFr8imiGwJgyVOdEZI0pQzcKqKCBDlawgdM2Jy1rTBmq85k8jSlDdU5P1pgyVOfcYY3JQdVjcWKzv7CCDezgWBib/YVzeeecLY1pQDc6WMEGdnAsjN3inLSsMYmnevy22NVdOBZGO104f1t8Qzsm8dyooIEOVrCBHRwLo50uxObYHJtjc2yOzbE5NsdWsVVsFVvFVrFVbBVbxVaxVWwNW8PWsDVsDVvD1rA1bA1bw9axdWwdW8fWsXVsHVvH1rF1bAPbwDawDWwD28A2sA1sA9tYtpgcdGMBBVTQQAcr2MAOYivYCraCrWAr2Aq2gq1gK9gKNsEm2ASbYBNsgk2wCTbBJtgUm2JTbIpNsSk2xabYFJtiM2xkSSNLGlnSyJJGljSypJEljSxpZEkjSxpZ0siSRpY0sqSRJY0saWRJI0saWdLIkkaWNLKkkSWNLGlkSSNLGlnSyJJGljSypJEljSxpZEkjSxpZ0siSRpY0sqSRJY0saWRJI0saWdLIkkaWNLKkkSWNLGlkSSNLGlnSzqgogRVsYAfHjf2MihMLKKCCBjpYwQZ2EFvBVrAVbAVbwVawFWwFW8FWsAk2wSbYBJtgE2yCTbAJNsGm2BSbYlNsik2xKTbFptgUm2EzbIbNsBk2w2bYDJthM2yOzbE5Nsfm2BybY3Nsjs2xVWwVW8VWsVVsFVvFVrFVbBVbw9awNWwNW8PWsDVsDVvD1rB1bB1bx9axdWwdW8fWsXVsHdvANrANbAPbwEaWdLKkkyWdLOlkySBLBlkyyJJBlgyyZJAlgywZZMkgSwZZMsiSQZYMsmSQJYMsGWTJIEsGWTLIkkGWDLJknI3eA0NsgSEegQoa6GAF28Lo2Pk8kcZEsxsdrGADOzgWRsdeWEABsTk2xxYNOZ890ph/Vlv84mjICwVU0EAHK9jADo6FDVvD1rBF67UYs2iyHssbTXZiNNmFBRRQQQMdrGADsXVsA9vAFi0yX5FhMTWsztkhFjPDblTQQAcr2MAOjoXRDBdiK9gKtoItmmHEQkYzXNjADo6F0QwXFjBsFqjgy9bmtG6LqWQ3VrCBHRwLZ7/dWEABFcSm2BSbYtOwSeBYaAdYQAEVNDBsMQ5WwbDVwA6OhX6ABRRQQQPDNgIr2MAOjoX1AAso4LSVGJ3Zxzc6WMEGdnAsnH18YwEFxNawNWwtisWW2tmUO5tyZ1PuNE6ncTqN02mcTuMMGmfQOAPbwDawDWyDxhk0zqBxxmqcmFh2YwEFXI1TzlA4cW3KMb3sxgZ2cDVOTC27sYACKmggtoKtYCvYymqceK/WjQUUUEEDHVyNU85QOHE1TpHVOEUPsIACKmigg6txijawg6txih1gAQVUcG3KMUnuxgo2sIOrcWKS3I0FFFBBbI7NsfnqoZgO10oM6tnoJxoYFWKTOxv9xAZ2cCw8G/3EAgqooIHYGraGrYXNA8fCfoAFFFBBAx2sYAOxdWwD24i6se2MusZsNLCDa3TiFVs3FlBABQ10sIIN7CC2gq1gK2t0Ym7djQY6WMEGdnCNTsytu7GA2ASbYIvujpGM+XJtTje0mC93o4AKGuhgBRvYwVjePjH6+MICCqiggQ5WsIHTNqcLWMyXuzD6+MJpm69Uspgvd6OCBjpYwQZ2cCyMnfuF2Cq2ii26e75g02IOXJNYF9HHFxZQQAUNdLCCDewgto6tY4uOlRjU6E2N4YvevHAsjN68sIACKmig3xgT1Np8VZPFVLQ237VpMRXtxgrG4vTADsbizOCPqWjNom603oUCKmjgtM1XqFtMRbuxgdNmsZDReidG682beRZT0ZrFQkZfWCxO9MWJsVV7FIut+kIHK9jADo6FsVVfWEABsTk2xxYbrceix0Z7YQGjWAtU0EAHK9jADo6FsYFfWEBsDVvDFpuyx+qOjbbGeouN9kIBFTRwLs68emAx56nVWIWxv7hw3Bhznm4soIAKGuhgBRvYQWyxTc5XU1pMabrRwQo2sINjYWyTFxZwFpvvTbeYsXRjAzs4Fsae4cICCqiggdgUm2KL4J+vYrGYkHSjggZGsRioaIb57hOLqUcXRjNcWEABFTTQwQo2EJtjq9iiGeblEIuZRTdWsIEdHAujGS4soIAKYmvYGrZokXlJxmJyTZvPiVtMo2nzXQwWE2ZaXA6JCTM3joWRnhcWUEAFDXSwgtgKtoItVvd8CYTFHJcbHaxgAzs4FsY6ni8atXixzo0ORrEW2MAOjoWxji8soIAKGuggtoqtYqvYGraGrWFr2Bq2hq1ha9gatoatY+vYOraOrWPr2Dq2jq1j69gGtoFtYBvYBraBbWAb2Aa2sWwxo+bGAgqooIEOVrCBHcRWsBVsBVvBVrAVbAVbwVawFWyCTbAJNsEm2ASbYBNsgk2wKTbFptgUm2JTbIpNsSk2xWbYDJthM2yGzbAZNsNm2AybY3Nsjs2xOTbHRpZUsqSSJZUsqWRJJUsqWVLJkkqWVLKkkiWVLKlkSSVLKllSyZJKllSypJIllSypZEklSypZUsmSSpZUsqSSJZUsqWRJJUsqWVLJkkqWVLKkkiWVLKlkSSVLKllSyZJKllSypJIlMX+nxSXFmL9zYwGnIi4TxqSdGx2civnCHotJOzd2MBRzhx3Tc3pcw4vpOTca6BMlsC6cHdvjwlLMcelxYSnmuNzYwPi78c9mv/W4MhJzXG4sEy1QQF04O6DHSXzMOrmxgg3s4FhYD7CAAiqIrWKr2Oam3CV+29yUbzRw/rM4rY7pIzc2sINj4dyUbyyggAoaiK1j69g6to5tYBvYBraBbWAb2Aa2EbZYWaOD48aYX3JjAQVU0EAHK9jADmIr2Aq2gq1gK9gKtoKtYCvYCjbBJtgEm2CTsHmggxVsYNha4FioB1hAAdcRaT93aicWMP7uCFTQQAcr2MAOjoV+gAXE5tgcm2NzbI7NsTm2iq1iq9gqtoqtYqvYKraKrWJr2Bq2hq1ha9gatoatYWvYGraOrWPr2Dq2jq1j69g6to6tYxvYBraBbWAb2Aa2gW1gG9jGso3jAAsooIIGOljBBnYQW8FWsBVsBVvBVrAVbAVbwVawCTbBJtgEm2ATbIJNsAk2wabYFJtiU2yKTbEpNsWm2BSbYTNsZMkgSwZZMsiSQZYMsmSQJYMsGWTJIEsGWTLIkkGWDLJkkCWDLBlkySBLBlkyyJJBlgyyZJAlgywZZMkgSwZZMsiSQZYMsmSQJYMsGWTJIEsGWTLIkkGWDLJkkCUxCabP51ssJsHcqOBUzEddLGa+3NjAqYjr4DHzpcfF75j5cmMBBZyK+Sp5i3cudQtbBEhcuo43Lt04bfOV+hZzZ3pcuo7XLQV6vG2pzwdKPGbU9Pk5J48ZNTdO23yCw2NGzY0OVrCBHRwLI0AuLKCA2Aq2gq1gK9gKtsiHeYnZY8JMjJnHhJkbHYx/Fhg97zEk0fPzErPHJJgbDXSwgg3s4FgYHVtjqKNjL+xg/F2ZGB17YQEFVNBAByvYwA5iq9gqtoqtYqvYKraKrWKr2Cq2hq1ha9gatoatYWvYGraGrWHr2Dq2jq1j69g6to6tY+vYOraBbWAb2Aa2gW1gG9gGtoFtLFvMfLmxgAIqaKCDFWxgB7EVbAVbwVawFWwFW8FWsBVsBZtgE2yCTbAJNsEm2ASbYBNsik2xKTbFptgUm2JTbIpNsRk2w2bYDJthM2yGzbAZNrKkkCWFLClkSSFLCllSyJJClhSypJAlhSwpZEkhSwpZUsiSQpYUsqSQJYUsKWRJIUsKWVLIkkKWFLKkkCWFLClkSSFLCllSyJJClhSypJAlhSwpZEkhSwpZUsiSQpYUsqSQJYUsKWRJIUsKWVLIkkKWFLKkkCWFLBGyRMgSIUuELBGyRMgSIUuELBGyRMgSIUuELBGyRMgSIUuELBGyRMgSIUuELBGyRMgSIUuELBGyRMgSIUuELBGyRMgSIUuELBGyRMgSIUuELBGyRMgSIUuELBGyRMgSIUuELBGyRMgSIUuELBGyRMgSIUuELBGyRMgSIUuELBGyRMgSIUuELBGyRMgSIUuELBGyRMgSIUuELBGyRMgSIUuELBGyRMgSIUuELBGyRMgSIUuELBGyRMgSIUuELBGyRMgSIUuELBGyRMgSIUuELBGyRMgSIUuELBGyRMgSIUuELFGyRMkSJUuULFGyRMkSJUuULFGyRMkSJUuULFGyRMkSJUuULFGyRM8s8cAOjoVngLRAARVcZwcqFWxg1B2BY+GZGicWUEAFDXSwgg3EptgMm2EzbIbNsBk2w2bYDJthc2yOzbE5Nsfm2BybY3Nsjq1iq9gqtoqtYqvYKraKrWKr2Bq2hq1ha9gatoatYWvYGraGrWPr2Dq2jq1j69g6to6tY+vYBraBbWAb2Aa2gW1gG9gGtrFsdhxgAQVU0EAHK9jADmIr2Aq2gq1gK9gKtoKtYCvYCjbBJtgEm2ATbIJNsAk2ssTIEiNLjCwxssTIEiNLjCwxssTIEiNLjCwxssTIEiNLjCwxssTIEiNLjCwxssTIEiNLjCwxssTIEiNLjCwxssTIEiNLjCwxssTIEiNLjCwxssTIEiNLjCwxssTIEiNLjCwxssTIEiNLjCwxssTIEiNLjCwxssTIEiNLjCwxssTIEiNLjCwxssTIEiNLjCwxssTIEiNLjCwxssTIEiNLjCxxssTJEidLnCxxssTJEidLnCxxssTJEidLnCxxssTJEidLnCxxssTJEidLnCxxssTJEidLnCxxssTJEidLnCxxssTJEidLnCxxssTJEidLnCxxssTJEidLnCxxssTJEidLnCxxssTJEidLnCxxssTJEidLnCxxssTJEidLnCxxssTJEidLnCxxssTJEidLnCxxssTJEidLnCxxssTJEidLnCxxssTJEidLnCxxssTJEidLnCxxssTJEidLnCxxssTJEidLnCxxssTJEidLYhJin/OKPSYh3qhg3DvogRVsYAfHjfW8L3JiAQVU0EAHK9jADmIr2Aq2gq1gK9gKtoKtYCvYCjbBJtgEm2ATbIJNsAk2bqfEzMMLFZtiU2yKTbEpNsWm2BSbYjNshs2wGTbDZtgMm2EzbIbNsTk2x+bYHJtjc2yOzbE5toqtYqvYKraKrWKr2Cq2iq1ia9gatoatYWvYGraGrWGLANETx8J+gNHSLVBABWfdOQPeY47hjR0cCyMqLiyggAoa6CC2gW1gG8sWcwxvLKCAChroYAUb2EFsBVu0/5yF7/Gyrxs7GP9sXsGIl33dGAvZAwVUcC7k/Lyix8u+bqxgAzs4Fkb7X1hAARXEptgUm2JTbIrNsBk2w2bYDJthM2yGzbBF+48Y9Wj/CwsoYNhiBUT7X+hgBdvC6OP5lLqf8ycvdDD+WQ1sYAfHwujjCwsooIIGOoitYWvYGraOrWPr2Dq2jq1j69g6to6tYxvYBraBbWAb2Aa2gW1gG9jGsp3TLi8soIAKGuhgBRvYQWwFW8FWsBVsBVvBVrAVbAVbwSbYBJtgE2yCTbAJNsEm2ASbYlNsik2xKTbFptgUm2JTbIbNsBk2w2bYDJthM2yGzbA5Nsfm2BybY3Nsjs2xOTbHVrFVbBVbxVaxVWxkSSdLOlnSyZJOlnSypJMlnSzpZEknSzpZ0smSTpZ0sqSTJZ0s6WRJJ0s6WdLJkk6WdLKkkyWdLOlkSSdLOlnSyZJOlnSypJMlnSzpZEknSwZZMsiSQZYMsmSQJYMsGWTJIEsGWTLIkkGWDLJkkCUxcXPMZxQ8Jm7e6GCbKIEdHAtngIz5JWGP2Zo3ChgKCwxFD3Swgg3s4FioB1hAARXEptgUm2JTbIrNsBk2w2bYDJthM2yGzbAZNsfm2BzbDJBRYrXMALnRwQpOW4kVMAPkxrFwBsiNUTfWZo0KsbJqAzs4Frao4IFzeUtsUTMURonlbQoa6GAFG9jBsbAfYAGx9bCNQAMdrGADOzgWjgMsoIDYBraBbYStBTawg+PCGpMxbyyggAoa6GAFGzht850ZNSZjXjhD4cYCCqiggQ5WsIHYIgnmYzw1ZmCO+XxLjRmYYz7BUeOVZTc2sIOxvD4xev7CAgqooIEOVrCBHcRm2AybYTNshi16fr51o8Z8zxunTWNIoucvHAuj5+e7+2vM97xRwGnTGJLo+QsdrGADOzgWRs9fWEABsVVsFVvFVrFVbBVbw9awNWyRDxoDFfkwLwPUmO95YwUb2MGxMPLhwgIKqCC2jq1j69g6to5tYBvYBraBbWAb2Aa2gW1gG8sW8z1vLKCAChroYAUb2EFsBVvkw3whS435njdOxZyIXmOS541TMeek15jkeWMHx8I4aLiwgFMxX8hSY5LnjQY6WMEGdnAsjAC5sIDYIirmxPka0zlvbGAHo+6M15jOeWMBBVTQwLDVwAo2MGyxAiIqToyouLCAAipooINxkS+W4bykeGIBBVTQQAcr2MAOYmvYGraGrWFr2Bq2hq1ha9gato6tY+vYOraOrWPr2Dq2jq1jG9gGtoFtYBvYBraBbWAb2MaynbM1LyyggAoa6GAFG9hBbAVbwVawFWwFW8FWsBVsBVvBJtgEm2ATbIJNsAk2wSbYBJtiU2yKTbEpNsWm2BSbYlNshs2wGTbDZtgMm2EzbIbNsDk2x+bYHJtjc2xxKSL2AedszQs7OG0t/m5kyYUFnME0HzCqMS9zzKeKaszLvHEG3nxFVY15mTfOwDuXIY4fLpyBN2fR1ZiXeaOCM/DmTL4a8zJvrGADOzgWxvHDhQUUUEFsHVvH1rF1bB3bwDawDWwD28AWxw81hi+OHy5sYAfDNgc15mXeWEABdWHs/eeMxhqzKm8UUEEDHaxgAzs4Fgo2wSbYBJtgE2yCTbAJNsGm2GLfPd87XmMi5I0CTvF8yVWNiZA3OljBBnZwLIx994UFFBCbY3Nsjs2xOTbHVrFVbBVbxVaxVWwVW8VWsVVsDVvD1rA1bA1bw9awNWwNW8PWsXVsHVvH1rF1bB1bx9axdWwD28A2sA1sA9vANrANbAPbWLaYCHljAQVU0EAHK9jADmIr2Aq2gq1gK9gKtoKtYCvYCjbBJtgEm2ATbIJNsAk2wSbYFJtiU2yKTbEpNsWm2BSbYjNshs2wkSVGlhhZYmSJkSVGlhhZYmSJkSVGlhhZYmSJkSVGlhhZYmSJkSVGlhhZYmSJkSVGlhhZYmSJkSVGlhhZYmSJkSVGlhhZYmSJkSVGlhhZYmSJkSVGlhhZYmSJkSVGlhhZYmSJkSVGlhhZYmSJkSVGlhhZYmSJkSVGlhhZYmSJkSVOljhZ4mSJkyV+ZokFOljBUNTAsfAMkBNDMQIFVNBABys4f9CcnFBj9uONY2EEyIXT1kMcAXKhgtM2JzLUmP04RvyKCJALGzht4/xnY2EEyIUFFFBBAx2sYAOxKTbDZtgMm2GLABnx22aAvK4NxTqcCbK4Je6JBzxTZHFJLIk1sSVOXk9eT15PXk/emrw1eWvy1uStyVuTtyZvTd6avDV5W/K25G3J25K3JW9L3nZ6S3BLfHoleMD9SFwSn95Ypf30xjrtltgT18QtcU884HF6o7dGSTzP/OKaa7ym8UYHK9jADo4bz8mSFxZQQAUNdLCCDewgtoKtYCvYCraCrWAr2Aq2gq1gE2yCTbAJNsEm2ASbYBNsgk2xKTbFptgUm2JTbIpNsSk2w2bYDJthM2yGzbAZNsNm2BybY3Nsjs2xOTbH5tgcm2Or2Cq2iq1iq9gqtoqtYqvYKraGrWFr2Bq2uLIZV0/OyZIXVrDdV0/OyZIXrist12TJEwsoYCTJvANc65kY87ZurWdiXNwTD/hMjItLYkmsiS2xJ07ekbwjeQfemDu5uCSWxJrYEntivOdbGOOmwvkWxgvnqMc1+HPe5IVxNa0EdvBcwnmIEBMnF5fE5xJ6sCa2xJ64Jm6Je+IB65G4JE5eTV5NXk1eTV5NXk1eTV5LXkteS147vTXYEnvimvj09uCeeMDnMcnFJfH5d+b+q53HDxeXxLFsccu5nccPF1tiT1wTt8Q98YDP44eLS+Lkbcnbkrclb0velrwteVvy9uTtyduTtydvT96evD15e/L25O3JO5J3JO9I3pG8I3lH8o7kHck7knfg7ceRuCSWxJrYEnvimrgl7omTtyRvSd6SvCV5S/KW5C3JW5K3JG9JXkleSV5JXkleSV5JXkleSV5JXkleTV5NXk1eTV5NXk1eTV5NXk1eTV5LXkteS15LXkteS15LXkteS15LXk9eT15PXk9eT15PXk9eT15PXk/emrw1eVNe9ZRXPeVVT3nVU171lFc95VVPedVTXvWUVz3lVU951VNe9ZRXPeVVT3nVU171lFc95VVPedVTXvWUVz3lVU951VNe9ZRXPeVVT3nVU171lFc95VVPedVTXvWUVz3lVU951VNe9ZRXI+XVSHk1Ul6NlFcj5dVIeTVSXo0rrzy4Jx7wlVEtWBJr4tPVgz1xTXy6RnBPPOAro04uiSWxJrbEnrgmTt4zo2JC1DizSGMcziyKeVDjzKKLLbEnrolb4p54wGcWXXx6LVgSa2JL7Ilr4pa4Jx7wmUUXJ68nryevJ68nryevJ68nrydvTd6avDV5a/LW5K3JW5O3Jm9N3pq8LXlb8rbkbcnbkrclb0velrwteVvy9uTtyduTtydvT96evD15e/L25O3JO5J3JO9I3pG8I3lH8o7kHck7kncsbzuOI3FJLIk1sSX2xDVxS9wTJ29J3pK8JXlL8pbkLclbkrckb0nekrySvJK8krySvJK8krySvJK8krySvJq8mryavJq8mryavJq8mryavJq8lryWvJa8lryWvJa8lryWvJa8lryevJ68nryevJ68nryevJ68nryevDV5a/LW5K3JW5O3Jm9N3pq8NXlr8rbkbcnbkrclb0velrwteVvytuRtyduTtydvT96evD15e/L25O3Je+VVDx7wlVcnn64RrIktsSeuiVvinngsLldGnRy/cc4efbEk1sSW2BPXxC1xTzzgM6MuTt6SvCV5S/KW5C3JW5K3JG9JXkleSV5JXkleSV5JXkleSV5JXkleTV5NXk1eTV5NXk1eTV5NXk1eTV5LXkteS15LXkteS15LXkteS15LXk9eT15PXk9eT15PXk9eT15PXk/emrw1eWvy1uStyVuTtyZvTd6avDV5W/K25G3J25K3JW9L3pa8LXlb8rbk7cnbk7cnb0/enrw9eXvy9uTtyduTdyTvSN6RvCN5R/KO5B3JO5J3JO/AK8eRuCSWxJrYEnvimrgl7omTN+WVpLySlFeS8kpSXknKK0l5JSmvJOWVpLySlFeS8kpSXknKK0l5JSmvJOWVpLySlFeS8kpSXknKK0l5JSmvJOWVpLySlFeS8kpSXknKK0l5JSmvJOWVpLySlFeS8kpSXknKK0l5JSmvJOWVpLySlFeS8kpSXknKK0l5JSmvJOWVpLySlFeS8kpSXknKK0l5JSmvJOWVpLySlFeS8kpSXknKK0l5JSmvJOWVpLySlFeS8kpSXknKK0l5JSmvJOWVpLySlFeS8kpSXknKK0l5JSmvJOWVpLySlFeS8kpSXknKK0l5JSmvJOWVpLzSlFea8kpTXmnKK015pSmvNOWVprzSlFea8kpTXmnKK015pSmvNOWVprzSlFea8kpTXmnKK015pSmvNOWVprzSlFea8kqvvPLglrjDZ0a5BYdrfnqi6ZlRF2tiS+yJa+KWuCce8JlRFyevJa8lryWvJa8l75lFc3Z90zNbLvbENfG5nCO4Jx7wmS0Xl8SSWBNbYk9cEydvTd6avC15W/Ke2TI/k930zJaLLXF4a2wDZ7Zc3BKHd86qb3pmy8lntlxcEktiTWyJPXFN3BInb0/ekbwjeUfyjuQdyTuSdyTvSN6RvAOvHUfiklgSa2JL7Ilr4pa4J07ekrwleUvyluQtyVuStyTvmS3zs93Nzmy5+MyWuc3b+U3WI1BBA8/iHlwTt8Q98YDPMKkhOsPkYkmsiS2xJ66JW+KeeMCWvJa8lryWvJa8lryWvJa8lryWvJ68nryevJ68nryevJ68nryevJ68NXlr8tbkrclbk7cmb03emrw1eWvytuRtyduStyVvS96WvC15W/K25G3J25O3J29P3p68PXl78vbk7cnbk7cn70jekbwjeUfyjuQdyTuSdyTvSN6B148jcUksiTWxJcbrV8j04PPvz52InwcYrQSXxJJYE0f9+Q7K5mc+XFwTx++ac6ubn/lw8YDPfLi4JJbEmvj0erAnrolb4tM1d4J+9vicyt2uScUX18Qt8bnMMVZnj5989vjFscyRk9ek4os1sSX2xDVxeHuM7dnjPZb57PEe43n2eI9xOPu3x288+/fimrglPmvG7zr7tMf2cPZIj98SnzGOY4Hzk+gnnlt8j63k3OIvlsSa2BJ74pq4La7n1jxfPtfquTXPl8u1em7NF1tiT1wTt8Txa4cED/jc+i8uiSWxJrbEnvisOddKPTvn4pL4rGnBmtgSe+KauCXuiQd8dsX8SHOrZ1dc7InPmjW4Je6JB3zuNS8uiSWxJj5rtuCeeMBnt8yp/K2e3XKxJNbEltgT18SnN7af6JZyxPYT3XJxdMvNJbEk1sQWHNtPdNTNNXFL3BMPuB2JS+LKmLQ0bi2N27mHO39jT+PW07j1NG49jVtP49bTuJ17uHOseuP39jRuPY3bSOM20riNNG5D+V0jjdtI4zbSuI00biON22DczgmyN591JPiso8EtcU884HLWseCSWBJrYkvsiU+vB7fEPfGA5UhcEkvi01uDT28L9sQ1cUvcEw9YT28PLoklsSa2xJ64Jm6wHawLK4yzSWJNbInTeFpN3BL3xAP2tB49jaen8XRNbIk9cVqPntbjlRuxLjyN55UbJ5fEklgTp/VY03jWNJ41jeeVGycPuKX12NJ6bGk9xhFzmRPf2znF9uaoX2IdRZ7cPODIk5tLYkkcv6vEmEee3OyJa+KW+PTGOJx5cvKZJxeXxJJYE1tiX3xOmS1zqnQ7p8aWOSW6nVNdy3whVzunul585sDF4Z3Tzto51fVmTRxekWBPXBO3xD3xgM8cuPj0arAk1sSW2PldZ1/PaXDtnLp6syTWxJbYE5/Lf9ZsiXviAZ/9rrH8Z7/P5zraOXX1Zk1siT1xTdwS98QDPvv94uT15PXkPfs9buefU1dvrolb4p54wGe/X3x6YxzOfr84vBbb0tnvcan0nLp6/+81cXgtlvPs94sHfPb7xSWxJNbEBp+9HGcO5/TTmyWxJrbEnrgmbol74gGP5B3JO5L33KfHmcY5bfTm8++3YEmsic/lHMGeuCZuiXviAZ+9f3FJLIk1cfKW5C3Je/ZynKecUz9LnGucUz9vrolb4ljOOHcY57775LPHLy6JYznjOP+cEnqzJfbEpzfG8Ozxi3viAZ89fnFJfHp7sCa2xJ54eiWOCc8poTf3xAOOHr+5JJbgGKvo8ZstsSc+vRrcEvfEA65H4pL49MYYVk1siT3x6fXglrgnPr0xnu1IXOB+umIMo7+kxO+K/rq5JJbEmtgSx3LGfvycUnlzS9wTn97X7+rnlMqbS+LT68Ga2BJ74pq4Je6JT2+dXI7EJbEkPl06+eyv+Th/P6cw3twTD/jsr4tLYkmsiS2xJ05eTd6zR+YVsX5OKyzzSlM/pxWWFst87tcuLokl8Vknxvzcr13siWvilrgnPr0xzud+rcUYnvu1+XRlP6cVlnn1qp/TCm+2xFG/xu86918XD/jcf11cEktiTWyJ43fVGKvzOLbGOJzHsTV+y3kcW+O3nMexJ5/7votLYkmsiS2xJ66JW+Lk7ck7knck70jekbwjeUfyjuQdyTuSd+A9pxLeXBJLYk18emuww+c+cV4F7ue0vzKvAvdz2t/1b0tN3BL3xGnZJC2bpGWTtGySlk0scfJK8krySvJK8mryavJq8mryavJq8mryavJq8mrynvvNczzP/ebFlbE9+/0cW0/L5mnZPC2bp2XztGyels3TsnlaNk/LVtOY1OStyVuTtyZvTd6avDV5a/LW5G3J25K3JW9L3pa8LW2fVw4EX30d43n1bIxn6tmSerakni2pZ0vq2ZJ6tqSeLalnS+rZknq2pJ4tqWdL6tmSelZSz0rqWUk9K6ln5bDEnrgmbol74rHGTcqR2NcYytWzcwwl9ayknpXUs5J6VlLPSupZST0rqWcl9ayknpXUs5J6VlLPSupZST0rqWcl9ayknpXUs5J6Vix5LXnPY91zrM79+MWdcbt6NsYt9ayknpXUs5J6VlLPSupZST0rqWcl9ayknpXUs5J6VlLPSupZST0rqWcl9ayknpXUs5J6VlLPSmOfIqlnpbNPkc4+RdJ+VlLPSupZST0rqWcl9ayknpXUs5J6VlLPSupZST0rqWcl9aykntXUs5p6VlPPaupZTT2raT+rBzl2ThE7x0cLOaZpP6tpP6tpP6tpP6upZzX1rKae1dSzmnpWU89q6llNPaupZzX1rKae1dSzmnpWU89q6lnVNCaaxsTSmFgaE0vLZmnZLC2bpWXztGxpP6tpP6upZzX1rKae1dSzmnpWU89q6llNPaupZzX1rKae1UrvaE1j0ugdbfSOtrRsLS1bS8uWjo01HRtrOjbWdGys6dhY07GxpmNjTT2rqWc19aymntXUs5p6VlPP6iBjdWhiMtYOMtZSf1nqL0v7REv7REv7REv7RDtYNitH4pJYEidvSd50bGypZy31rKWetcK+2ORIzL7YhH2xpf6y1F+W+stSf1nqL0v7REv7REv7REv7REv7REv7REv7RLPkteS15DW2YTP62py+NqevLfWXpf6y1F+W+stSf1nqL0v9Zam/LO0TLe0TLe0TLe0TLe0TLe0TraX11Upiju2tc2xvqb8s9Zel/rLUX5b6y1J/WeovS/1lqb8s9Zel/rK0T7S0T7RB5thgfflB5vhB5njqL0/95am/PPWXp/7y1F+e+stTf3nqL0/95am/PPWXX/0Vy3z1V/C1j4vlv/Zfsfxp/+Vp/+Wpvzz1l6f+8tRfnvrLU3956i9P/eWpv1zpfU/niW70vhu972n/5Wn/5Wn/5Wn/5Wn/5Wn/5am/PPWXp/7y1F9e07LVkpjt3BvbuafjQ0/Hh56ODz2d03naf3naf3naf3naf3naf3lPy9bTsvW0bCMtW+oFT73gqRc8HR96Oj70dHzo6fjQ0/GhD9ZpPY7ErNN6sE5r6oWaeqGmXqipF2rqhZp6oaZeqKkXauqFmnqhpl6oqRdq6oWaeqGmXqipF2rqhapkSE3HctXIkGpkSLW0/OlYrqZjuZqO5Wo6lquextZLYtb7NZ/ndKX9Qk37hZr2CzXtF2o67rrm85zc2GfVxj6rpu22pu22pu22trRtpO229rRt9LRtpAyvabut6RippmOkmo6RWjpGaukYqaVrfS2dg7R0ra+la33X/Jbr7zAO13yV8++f24mdXBKf9yWjzrmdXGyJPfF5P3QExzj4vGZ+zSe5uCSWxJrYEnviqD9fY9ev+SQX98QDPrexi0tiSXx6JdgSe+KauCXuiQd8brcXny4N1sSW2BPXxC1xTzzgM7cvLomTtyXvmdvzUZ9+zS25uCZuiXviAfe0Tntapz2t057W6ZnnHtvwefzjsR2ePXJxSSyJNfG5/LF9ntl+8Vk/tsMz2y/uicf6+9fckotLYkmsiS2xJ66JW+IOn70Zv/2alxK/5Zp/crEnrolb4lwz/ZbzvCN+4zX/5GJJnH6LpN8i6bdI+i2SfoskrySvpjHUNIaaxvDMivO3a/qN53HUxQO2I3EaK0s1Lf2WKyviN15ZcXJNnH6Lpd9i6bd4+i2efosnryevpzH0NIaextCTy5OrJldNrppcNblqcl37tSO4Jm6Je+IBX8d4J5fEp3cEa2JLfP7G8Z//+Xd/+du//OM//Ntf/+Wf/8e//es//dNf/v4/1v/w//7y9//tP/7yf//hX//pn//tL3//z//+t7/93V/+P//wt3+Pv/T//u8//HP8+W//8K+v//dl/qd//l+vP18F//df//ZPk/7z7/jXx8f/tMdLYeNfz4VcBV43zn4pUT4uYfMzhlHBrK0C7dd/Lx//e/V7+V9XZliANh7/hjHnI0SF8bpN++FvsM0y6Lydei7E69rGKjHG0wqvuxx2VXihU6H9UqF+XKGuNVFrGoc+nhZoc7rMuSpLXQVel+V+KdA3v6HO9+yfv6GV9mGJ8XEJiScyooS8bnB+WKJs1ufrRsk9lK/7IePDGpu1Md88fA/m6xiI0ZT662JstkunhJYP18duIdrasuf7Zj9eiN2GWee8j3PDfJ200F7+awnfrFWbh5TnWn1dg/mwxHYprKylsPpRiU2F+VTAVWFOAv94LDabZ42P+J7jOXJWuf5aY7N9arzK7/wlR/3wl+wWo8XTzudPKaV8uBhS/tzFkLVlzDdsfLwYutk0WpHV8Ck5/ddtXDYrNr7ofGZvz+ldn1dYfTbfG/1xibpLDCMxnMWw8muJthmKQ9ZQHF4+XozdBlq1rAiveTHk1xqbDXS+Bfiu8TpC/LCG7gLU7i3jdT+TCsf43oYxPtww9tun9rV9+sdtsq3h69hiPh72YQ213WDYvVOT16XaD4N8uxyV31J9fLwc9f0YfroYTb43pHUcBPFmSMebR3x2vHvIt/0Zrer6Gflw6befsdslNVmj+bqW8uEuyfTt3bPZ29vFfine3T3PSRz3saOVzVi03TF0HxxD52Ou/muN/vYOyca7O6RthWc7JC9v75Bc3t8hub6/Q3J7f4fk/u4O6fGG8fEO6fH2Kf7x9rmtoUaN9mENH2//lF0Jbc0I0PbhyWZ5/1yvyvsne1V/4GRvt1baOnXW19W8D9dK9d3Jc19nz8dR0w7l15at9e30qu3d9NpWeJZedbydXu14P71aeT+9mryfXk3fTa/HG8bHLb/bPl9X04+1ff5yOF2e1/BxL8a8U/hhjdYeXeeS47CPr1PtlqP1tRyvK/ofL8f7J/K72LCyhvR1vPLxDqGX94/etouxTlCstI+Pm/r7J/L97RP5/v6JfH//RL7/wIl8/4ET+f4DJ/Lj7RP5/v6J/OM2afVbx01W+r1eTTbnBuP9S6Hj/Uuh40+9FPqK3pV+7fj4svDYbKDe11n8a1T6hwk6dsehZR3LltfYfpjku+WYnxC/l8PGx8sRbyZ5M8q3y+FlXayvR9ssh76/HNuto9a1daSW/VKJTolhH14nOrYxuu6IvRJVvlljbaavA/P+cY3dWVvp7e7Z+TS3fJiC5dhtqXKsuwfzwd/ycZndfSVf+eHpevnvaVpKeTeQny5Fuq30hxL78YiFvMbjdTd7Mx67IBrrOl4fPa+b3+79bu8uObvsF9fdutltbXXttaWmLbZ+ZUlcWBK3zca2u7JYpOmKxWO3nTxflrpbln2Z7pTp9btl+sqDF6cj7i+XEcro+G6Zti4bzJKbLWZ326hob2s9Df3eenp6kFa2d5+ehcK2xDoxk+1P2W63PW23+t3tth5st7WU767i6oUyYxNQWn5g7ai8vXa2JR6unf2IKBt99U0L6m57ba2uKQVpWeoXSnRZh2zdxvdKNNZL+7DEfhcmVtcuTOpuPHZ3otZ5mnn56Gzxk0OUwfliGeofL4jtrwOsn2Pt473GJ0d+nFqMj4+4dreCTMa9dk1FPjzRKrtbUtLWLlBaOtr6/e6v+dtXJOKVTO9dktiXeHZNouzuPTy8KFF295SeXpWIKb7vXpYo/hOh6u+H6uMNZDPFYL+hrvOC14aq36vRe1/pfhwf1vDd1D1fRzTV0znb12r4eFJj/1vWjfXXPmvzW96+f7ov8bTpHv+UjzeP3f2psU61hmzadhenquvarHrdxOm2yIpTc/344lfZXTN/eMuvbG9DPLznV3b3lx7P8Kz9/bt++3Htq2P8KJuVs7tR9Wwb2VV4umZ2t6ker5ntfaqna6bZn7xm/LBjrZld27T6Z3avi+q64uObg6G22VRVypo2IOnwsH6lxLpaq3r0j0r04+FFeP3wkHs7GmSZvxLpe1n2OplbRboeHxfZ3ZSwtYt55esq8Tqm+K2EvX29aLsUaxu1dAzzx6XYBerR2roIcbS0165fKdLHushzjMO/9WPWeaEfuyHdHqK2tYHMjzgcHy7H+IkRGT8wItsttdd1nKt57uhXNvdq66LK64rG8c0iXH2rfbf/3xZpxz0kNV9I/0ORUd9OkV2Jp3u78QPPmZTxA0+axEtS/9S9XR1cURmb3YwcuyOA+bmsNSh5ftpv88+P7ZKsKW7zg1GbJdldhmh17fB+2Vx/u5cWb2z9eBWvM8TXIemHd1pldwfK2H2b/nKZ+Ldny47t3LA1Ufj1a2RTZDv7UI2Vo5sbLrK76KWVac/pElHRryzJ0VPvyMfXzWR3H2t+0XDdCT/y1vbHH7TdaLVxEq9dvhPU86Mc90bbNhkr2yeUyroBrCVd9/r9SZby/iUrKW9fstqXePg8THn/kpWUH7hkJfIDl6xEfuCSlcjbl6yebyBjs4FsN1Tmj5Sq36vhfo/HK4vqN2usWWffr9FSoNXxzRq25u42/7jG9pmpZ5ffPqnx6PLb/rd0WTOUurX3a3j5Xo26zga0b37L7rGp0kn2YZvu3y2IlXX4bGX4xwvy/rXVT2q8v3KtrBB67S+Pj5dje9fL1z1aSQHytUGV1XWvU9iPB3V3u8p8nYG3zbq13WP7Yx2v6pCPJzjI9hIeE3vsaJvDqu2l4nVnNV/k+cNh1XY81gmJ2/HxeHx2AK/pAL58dAD/eK7lhydoXzlC3EyvkN0NK1kTT+SXaSdfOFattmYpvS7R6MfLsX2S6tnK3Z+LMN+kpUPdr9xXrS4rQepmEqzsHqWKk4PrjDUd/8tXrowM5fLK+Pj2/SdFiKFjtI8u9Ii/vaV+thxMknot0/G9q2cPf0x9/+rqJ8vx6Mfsn/FYnTu/MvDxmff2gapnN++l2vtnQrsf8/BMaFvi6ZsB2vtnQru7VY/PhHYPVT0+E9rda3p8JtTensT6fAPZnAntN9RHN+/3NZ7dvJfm7x9g7ms8O8Dc/5ZHN+9ld6fpYdNtSzxtusc/5ePNY/dk1aPbf9s01VVhvnf54zTt+xsAa8Kdp7t/r1Pw34rsHozSde1+aLpZ9cciuzA81iP643VPZFNkd/XeuBjKoEr9/R0nu0Ct66rsKyLK94q8zhjWgoy6K7JJVC/rUUSXIz/A8pUF6SzI+HhBthuaORtal483tCHvXzAf+gMXzIf9wAXz3YNWjw/9d7eaHh7670f10aH//qHZ9Wq4F+qHa3f/go5HjwXtSzx6LEiP7VspHj0W9EmNR48F6e421WvHohxQlTo+3Mj0+IHnV/T4kedX9Hj7+ZVPluTp8yt6/MDzK19Zlrpblh95fuWTMk+fX/m0zLPnVz4p8/T5FS0/8PzKdlket8DuhtPjV46V9u5Jxb7Eo8cstj/lC928u2v1sJv3S/K4m3d3rZ4+1fNJkYeR8IUftIuET8o8jYR9mceR8FmZh5GwL/M4Enb3oJ5Hwn7nSpVDjuPjUNAfeKDlk2OWJw+0qO5qPJtvtK3R2jqnnV80TRdvv9TQTx+N+6zMw0fjVNsPZLb2tzN7W+InMvvpo3G6u4Xz7NG4fYlHj8Z9UuLJo3GfHF883tCOH3kGU+0nDg7s/YMDe//g4PiRZzB1+xTWsw1tW+LZhrYv8egZzN2FPhlcYRv5jWfP3yY6dB0ova5s6Yc1dPt2wIenpfsaz05Ld7e0nr+tQn17Avb0bRXq26tbT95WofXt1wc9XYrN2yo+GY+nb6vQ3TXlx6c69QdeZqn17bdZbpfjC+cp25tbz85T9kvy+Dyljh84xfjCsuxOMT4p8/QUY1/m8SnGZ2UenmLsyzw+xdjdqHp8irFtgGf74v3PeXyQ80mZpwc57Sdeut7fT9ttiR8Z2KcHOdv7Xs8OcrYlnh3k7Es8Opre732evmhCd/eJHr1o4pOji6cvmtDtpJmH5+X7o7Z1O2K80uLjo7axuxHwbJ6Jbm/PPJtnorubXs9uee9LPLvlrcPfnmeiYzuH6Nk8Ex3t/Xkmun2f3tNA3D6h9SwQH28gY7OBlLfnmexrPJtnYtuHs57NM/mkxqN5Jp/8lkfzTOx4+zGXfYmnTff4p3z8dtNj+76LJ4+Z79LU13ckhm8+RbGtUdejt6NW/2aNtX2NOj7+OsjrBvrmcuuz56isvD970Mrbswf3JZ5tYFbenz1o5QdmD1r5gdmDJj8we9Dk7dmDzzeQzUuJ9xvqo+eo9jWePUf1SY1Hz1Htazx7juqTGo+eo7Lt96se7qH2NR7tofa/5dlzVM9rfPwc1b7Gs+eobHfv6elzVNsFefgclen701w/qfH+yn34HJXp9qTu2XNU+wV59hyV7T5k9ew5KtvdMXr6HJXtHsZ6+hyV7W7XPptvtx+PR89R7feWfPPtxbY5jrG3Xx60Xw7n+ME3Z8m2/W7Rs2mdtnsUy8qa+vfLy/N/v/Jtu/tFxbkIqZuVu/3s27PppeZPJ7T8ctlPnxd5OkfVfHsU8vRBOfPtQ+FP3w3xlaXZvNjBtleZDuNq84v1u0vz/Ee9/cKLfYl0eDU+LrH71NUPlHgYjXV/rnqX2DxQuV0rjzf7+gNTs63W94e0vj+k9e0hrf4jIbB7Luvnl2QXANs3CT4PgPozqdbs7QDYlni2qbX6p5Z4uLW297dW27/umteR7gJgd5Pp8R54f1zz6MGKzzbVhy8h+kqZzR1s2z2k9TgXdw9pPdzSdiUebmnbEg93Ne1H1s0XyuzWze47WI/XzXj/MGC8fxgw3j4M2H9Ye11RaNI//oKzbW9XPbt7Z+P9z13aePt7l/sSD6/zjve/eOnHD3zy0o8f+OalHz/w0Us/3v7q5fMNZHOdd7+hPrp7t6/x7O6d794j+PDy2Sc1nl0+2/+WR3fvvBzvNt2+xNOme/xTPv4QctE/8TpPk/VLmsrHs2C9vP+2S98+hSXrAn6VXefv7lc93VH69uWBj/ZynwzIs1fu7FaMOivGN7dE3/8cX3n/c3wu229cP5rg/EmNRxOcXXZr5fFzt777WNXTmbgubXs98uEMWN/dbno2A/aTJXk6A9Z1e1r1bAbsV5ZlMwP2szIPZ8B+UubpDNhPyzybAftJmaczYH33LsCnM2C3y/K4BfQHJlm5vj3Jal/i0azT7U/5QjfvbmM97Ob9kjzu5t07BZ8+d/tJkYeR8IUftIuET8o8jYR9mceR8FmZh5GwL/M4EnbvGHweCfud68Pnbt138wWezu99/0Ny7vvPBK7zne4ff6V6W6Qd6z59O9L87T8W2b2i59EHWD4p8eQDLO7bm7BPXhG4H9KxHrhru8eQfXcb6eFybO+HPXuk2ndPYz39hIPX7fswn33Cwev+yb9Hn3DYb6iyXqv5urzWN6tmd4Bija/Lpzd0if0WI9t3Ddp60ehrR6qbItslqaRrSsU/FNnd0/IVZzXNjhHrz0vU9Zavmo5v/lBi+1M87W/S9JgvjsfDQd1+GetofW1pR76e9ZVEjBd4nRta3gn/YUPbDutK1Vr1m2vGeJ2tfbfE2kFY/bjEfifDN3pG3SRif//7a/sax7FmTx4pif5QYzuzhWtimh6W/UMQ9R/4hpv3H/iG2yfHVk+f0PuszMMn9Lz/wPsuvL/9vot9iZ84V3r6hJ6Pt993sS/x6Am9T0o8eULvk/P6xxvaJ2WebmjjB9534ePt913sSzzb0D4ZkYcbWj3eft/FvsSjDe2TEk82tOP9o7N6/Mi8uOP9o7O6/TjWWB/8K+XDve/TEvLNEs+OEbclnh0jHu8fIR7vHx/WIu8fH+5H49Gh3b7Eo0O7T0o8ObTbzYdjPrqUIx/YtcclylFXiV++Zfe4ROGV/FLyLaTfStTdk1cPDw33NZ4dotbdc1dPz7jr9iNYDw8v6ye3oh4dXm5XLq2i+vH2UeXhTKm0b5PnFVRXEqul9/2M39pett/DfvBRj22rrEkSr9RIZ4T626vOt28ObG3dpiyva6K5jH6hzOtfro2sH2m6xR/K7N4d+OhlCZ/8Hm6wzKkj7du/Z715/cVlbH6PvXsF8pMST65AVn37462fbiZrX9lLnrjxh/HYfc/a1wp+3aT3D9ewjne3ke1S2Dr4UD8+rrF7+OoVQxyLdT82A7K9b1WIopI2EPH63SLjB4qYfbfIOpOSkqaz/LHIbrqzrS+Fv+I5zWc5fh/Y7ev561rHIx31/7HI/py9rXMpK98twvyLkY/7v1bEWBLvP1Ck6qbI9n3l7IDbL++X+63I7l6Vt3FvJ69bgfK9VWx13SS1Vso3ixyF5x+1fXNMfG1skqfn/XFMdkvS12Gr9dK+ObBlHRO8sH+vSLW1JNW0/8DPkd0qfpwnm1CquyLPpujW7XdpZH1q+HXw2DYLstmVN29lXcJPm0n57dC1bp8TWPP0XpgOS35fjro9MVFOTOzjGtuXUh3GS6mO/OaR9oVh5SvQkp/z+eP+4vmuOH/+7Pdd8e6uxNNjk/b28et2KR4em7TtmwN4PUXpNeXrHwdk+52B9QxWsZQlZdSvLEukxL0sbXOctHsEqlRlvsbr8PDDSyTt7ZdefrIcfNbpxenlt18Zk3GsxzFfPDbnKNt3/pV1D+x1VpyPHX87kd19LOvhmGyXQw7ytdSPl2M/JoWrrK+rL8dmTDbbrOs62HKTzYa/ewrKDlsvmjj65tRv+1nHdjCROc3KHr+vnN0DKg8//1V3N56efv6r9u3D1E8+/1XH9tMYzz7/tS3y9PNfdfduuIef//pkQR5+/mu7oaU3muRXEf1hQxv+/oa2u3f1eEPbPk71dEMb/f0NbfzEhjbe39Da7pmsxxva+LM3NFmTJk02F7Pa7haWy9oF+y+vfW+/1djN22hrd/M69ugfHjTuf8x6GMqk1c2PaT/wY/qf/GN0PVL1wvbNHZauM5wX1m/uOrmV5V4+DqO2u5VlY51/Wn5T7ReLrLZ54beLDIqMbxZxnsz0X86U/nDsuj204ZZ8eSXt8d0yut4Z9eL67aVJ07lHlWMzMtuQHeuSR54p/KXDYOeewet61Mcbf9vd3np2J3lb4tmd5O2PkePgquVR2iZjZXvOleaCq6QboL/tdra3tx4d03+yHFKYk/bxrYsm20e01wvKRinynW3ktd86uMkl+VVpfxjW7QfjeYnVMXJSl+8ui/aPG7BpefsMv+n2bqxxznWYbVpH948Xrr3PfNRQv11m7ZFfXDfb/u4dgc9uln1S4snNsrb7Ptazm2VfGY9dFnxWplOm+7fLrEF5nZ9vdj9t+7bBZ2tnX+LR2jH9s9dOHo9yfH/ttFSmfG93/GuovC6ab9bO9l7IOpy1dsiHobK9PXT4yusXu/7EL/LNVIDm26tK66VW8stzdL/9In/3cuwnS/Ho3kHz7YCMsraUY7hsBsTePeL6bEnSGh5tt2renru3LfHsiGv/Ywq3MeaUr03K7h7Pel14VI6Hi308sNsi6b2yLx5vH+uUsjtn2d3uengfo+3uyzxrnO1SPDzK2T6gVfIUKambxqn1/58Hf8V8k9O1/8DKGW+vnPcnwLTdra7XIFRWjh+bQ9DdO9i0yxqQrvnG6neLpBOeLxUx4WW5+ST9j0X83XWz/y3t4ArobkDevtO1X47B9xxeFy2+uWKY+/K6ivrdFVPWnWYrzb+7dtfM5Nf1Q/u4yO5BrUdrd3vHbhWQ18Xc1DG/bSDb63RtvYrFR/142uf2g2NsHv7LVbrfl6P+yUUezpFufftO92ePz7XdDa6n85vb9hbXD8xvVg5qfpnf/Puo7m5wPXq31XYjU1knN/OsbbMY9u5i7Cq4r5sfXn+5nSu/Fanv7+2238Y61gMB9ddDTflCkcIzGuWX67e/Fxlvn4fvSzw5D+/H2y8TeLpuq/xy+iy/LYe+vW777r7W61xkTXf75bWYf1iQ3ePZZZ3RtF8eOvlDkc2W+nCCWN/d2Ho4Qazvbmw9nCDWd1/HejxB7JNhXR9WbqW3b64bWUH0uuhdv11kvVVO2vHtIkqRvkmAp43zy1nib0tS/O3LK3334sFHh0OfLMWjyyt997q/qusqabUim+HYfhzz2TOeXX7gYcBPluTZM55997TWsyf5Pinx5Em+/U95+HzlJ+PxcFB3Lx58+oTl/sB7rDt89dfLxr9trbvXDv5IkYdHzX3/1sFnR819dy/r6VFz397MenjUvD9g1bWjUO0fn1p1ffuAdbsYtiZSqZl97wyvMP+h5PkPf1i97352eP9TXNJULNuM6KZ7+3qf2K+zQX59r1m37YzotXmo5fnD9pUiY31qU4fppoi8e+j9SYlHh967dwM+O/TejoYd6zDEjrSl/3E06vujUd8fjf7njkZhclzJU7B+H43djaKHo7Ev8Wg0XP7k0RhcKKubdtt+BerpQcz2HU+PDmL2GTYOLmLmN+t/JY5fw5AuDNdvFuEt8FbLN4s4j0N5ad/8OT7Wg54+fHNpZ/u5kodHIPUHXnvV6w+89qrXH3jt1X5cKeLyy13v3/aXtf6ZRyA2nPe7/HLG/Pti9DcXY1vh6QbSfuIQtf3EIWr7gUPU7SEZz7z2FAB/XI5drj58lUff3aN6PiL1T24ZU265ed2cDLXdGVXl6wfp7F9+29O03QXRnp468Nwzv53t7h6DenY1ZL8Y69zwdZC6W4zdEWZdl//S/I72hdEwbXwrLF+F/MNivP3mi/1yGM93u43NctQfuLDTf+AtoJ8sycNjot1tqodXZbbL8fSqzP7HPByR8QPvvdq2f+98TyZPkfxD//ftteq1kcgvr6z+/df4n1zk6W5zd5vp8W5z9B/YSew/jvVwt7lbOXwKquWv7Pw2qmN3t+rZ4cx2K1tPhPZ87f8PC7GbU8VTS+nKf/vCZsq7wHrTzULsNtK+XgFSRprv3dpvNbbfwXj2bMA4ts8GrFerjPxd6fqF3zKUx0fSpzT+8Fu2DwY0ihwtHYPULxVpvMC/Dftekb5e8l6Ocfh3hkSIDznSU22/D8nuw1jlKHyT6ig1B4h/qUxK5jLG98us3dUh6bm0L5bhJu+L67Eps/0qJfvOIz2co799veyTIusub8mPl/+xyP4H1fSD2reHV9cVoxerfLtMWtmaJln+oYzIn15mTk1c+666WUuyP+XjGY4U2F8roqunxY6Pi/Tt/V46wCUfB3v5bUl2G92zD82N3W0nk/Vg9etCWD7HOX4rsn2j5bNPkY/tzavHH98e+vYnVb+yJJuPbw/dNtDTr+Z+sjRP3zI8to9RPfr49nZJnn5PcOyumDz7nuAn2/2j7wl+lm68w+bQ2j6OJXv7FsEnJZ7cIhj29i2Cz8bD2A2q14/HY3/EM5RhHR++3fuzIjx5cYz24QGcvf2CzM+Wg49tHfm6+hdmGNih630gv05U+i3pbf/q0rUgPc8Pll8vEoztvajOttpHvl9anhextm6GW8sPmv+hyNs3XffL8cur6MpmOezPXQ6m1NtIjz39cTnqn7ocfuT3t9tmOfr7F9aG/8Dknk+W5NmFtbH7tNWzC2v75Xh4Ye2TH/NwROoPfHBoHwH53ml+/dvvW0l9d4rgNs7EVtOI//IluP6FInUdjUjLL1r6vUj9s4s8vMA3dre0nl7gG+0HXug+2g+80H2/ckrjdC0/a/D7uO5uaj26xDe2308bnFCP9uE31sfuuatfvlvf2sc1tvden3xjfV/i2TfWR3//yeexe7lg4fU55cjTL/6wILuJqHVlSK2bz5uP3dexnn6cZ2y/jvXo4zzPN5Dx8Qay21BFeIpM0ly232tsv4rl6+pGzU8afGk5Cm891rJZjt09vjVZwdpm+9g9dPX4qsQoP3BVYnc/6wtXJYa+fVXiC0uyuyqxvaX1/KrEfmkeX5XY3dd6eFViW2JNKVMfmxLj7WsS241+3V/3/J7T3zf6be8xc+J1YfGb/ZuPrFI6/1bjvOb9XgPPi+XbI801Z2HIx5+pLsexfWtr462to3y7SuV98K3tqrx94eqTkX20lexnPSvPxefXaX5t6rQyK8XKx1OnX3n37qtYPplT+uyEsxzba1dPJy7sZ6Y+moWx/TVPZ2Hsh+TZj3kNSXv/bHE70b8c62DgdYKYp6YeXyhiyvccf3k87vdNbf8Y1k9UeXiidh7ivnumNm9Pvn+qVg75gUmun6xm43ah225s353lOm8a/8Dq2b7EkokM86Mzm1+zreK8pca1frOKls51vV/eyvmlKrLOuFR+mUL4pSoHXzeTWjZVtve0mh0c9uWjx/qFKg+/gDfvQ+zuAj2bNzvv7vxEH25vaj3sw0+3/4Pt37+76fb1sTQ9dNcAdvzAKrKfyFv7kby1H8lbsz99PQtjK9uIsvoTrbj9ppbyEF3V3Ta3e2JLW+XWUn7Dif+e/9u7XM/mM7x2Uj9w6WBevHr/2sH5HrL3T5JfdfTds+TPluXp5YNXnR+5fvDZ5st3gl7c5ePN95Mm0NQE5cMq/vYDh18a32N3slqPd68U7Zfl6USNcmy/sfXwhHff0o+mauxf83Wwdg7J36L50lvL1tp5Ffn4FWyvIdl+KG+sNzm1fHL2pSrKzZEX9u9WMR5wyeffX3uFGu/NnY/MbhZl91DXsyfc9svR/svP8/wXy7Hb7h99nP6TGo++Tv9ZjSefp/9k9Uo5/qtzhy9uJMIhpRzbcW3vzk/4rMaTaU5zqvX7Ob0fEeW3+PfHdc1QUqn121XSsrxRpbOO+7fjRNf7AzR/tOSrVda0nLeq8KFXfSMgeeNVvp7+h4D85C3A+Rtm/aOPw+3fjMw74qp+eG1xX+LZg/P7Ek+ucH7y9Yd1a2DkWdhf+oDEk4dE9p/2eDYW8vbUoE++I8Nn6Y62++TKtshKAD9sfLMIT6l52Xwq85MlGekrs9/+ts666uz7r+ztbtcYXz7avZT5C0Xsu0V4ataGfrfI+qTjq179ZhHn7S5evjuwvP3HXL/7XSpf13Re9XZrZzsRRXkQw/JhyW8nKOV4+7WZn9V4dFhSytsvztwPCBcKRGvdDEjZfoKbd5Hm24tfWA5bT7291ovtlmOzjTz8ENuryG539fRLbLuf44XL+FI+/DmfFFmPmb0u/9XvFuE77V63AzvePsHZ13h2gvNJjScnOJ98ddd5UqC6f9y+8vaLsz5dEEkL8vGI7G5/ld6E7zM3/zhdS5HtnYT0mvfXOcG2zv7DLzw1mvbEQ75UZF3qk/z1zz8U2T01NGRdSh35Vby/P1dSyu6xrrpetNLyM5rDv7IkD7+I+qqyCdmnn0R9Vdm+VPDJN1FL0e034Z59FHVf5elXUV9Vdt/efPZZ1M8W5dl3UT9toXWw9GkL7eswiVlq39XZfSLr4RugS9m+ZPDZK6BfRXR7P+7JO6BfRXYTVJ6+BPqz1C3c7HH5KHWPd7N/N6mkMnG3ps9h/P4k77bEOs0oeUv7SonOfezev7UUr4t86YOK43sl1idKXli+9UN4GVbp5XvDyb3r0vVbP6TImmtf8nXTr5TQ9YbTYsf3Stg68Hx1pHyvBG83MPveWNh6KKx4mlX+e4nXwfx4O9q30w3XzPTXpb00SffQ5yX4KMBrj/V+ifqtEsaEhvzs/1dK+LqtNj8c9b0S3A/2+r0f4nwLJH/O7ysl6mo0zd8j+kKJwqeE5vuRPyzxOk/cXaLlqZZfPyjWni9H+nxy/9ZqlSN9vDW96OVLJdaBmBxq3yzBtwDV3y5h310K9iU2vlfCGYu0U/zuUvRvNdrDDyqU0t79tNv7D22V8hNPbb2qbN/lUjhVPkpO8t/nxZTdk1t9rN18z295+i+qbKdbO4/nu9vmIYOyu6L5OglYU0j0yFv8+P7S1O3SbOukOPM8U/O/qLM7d3/0ubhPfxPB+OL67d/U08z4fGz49To8Fp4PEL9apzEt5VVzN8a7p7qKpg+7D/3mljMqd8Rq3vv8oRt2z3U9fRryVWX7Abgnj0N+UmPdSJJvj8kXfs34gV8z/txf48L7m39Zkt9/TXyP9M1fs6/x07+mbTNhvy+heV676uPj7V62by404zSpfT+9K29Y8VrKt5Olrte5v3hs1/X4ge0/Zgm9u8Vsa/zAFvMaCSVvqx+736Nv3/7Y13h2++OTGh/e/vjvr//yD//413/9H3/7l3/8h3/767/88/97/bv/nKX+9a//8D//9k/Xf/3f//7P/5j+33/7//7f+//5n//617/97a//53/833/9l3/8p//17//6T7PS/P/+clz/8d9eTWd/J63Lf/+7v5TXf+/9dbDV+/DXf9fXf9dXyPzd6+Syzv+/nP+g/N18v8V//8+5hP8/"
2485
+ "bytecode": "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",
2486
+ "debug_symbols": "vf3bruXMkV6Bvouu+4IZhzz0qxhGQ27LhgBBbcjdG9ho9LvvmUEyR1SVVy7WmuvfN6ohqSoGZ5Lx8ZQk//NP//Mv/+M//ve//PXv/+vf/u+f/vm//eef/sc//vq3v/31f//L3/7tX//873/9t7+//tf//NMx/2O0P/2z/tOfRv/TP/vrjxF/lOO4/izXn3L9qdefdv3p15/1+rNdf/brz6teueqVq1656pWrXrnqlateueqVq1656pWrnlz15KonVz256slVT656ctWTq55c9eSqp1c9verpVU+venrV06ueXvX0qqdXPb3q2VXPrnp21bOrnl317KpnVz276tlVz656ftXzq55f9fyq51c9v+r5Vc+ven7V86teverVq1696tWrXr3q1ateverVq1696tWrXrvqtateu+q1q1676rWrXrvqtateu+q1q16/6vWrXr/q9atev+r1q16/6vWrXr/q9Ve99vpzHNef5fpTrj9f9UqZYDf4Da+SRSe8apb6T3+S2QylTXj9ZTkmvP6yyITXXxaf0G7oN4wLZg+cUG54LYWWCXqD3eA3vCrrVMxWOKFfMDd61QnzL8+CczPXuYRzO9c+od8wLpib+gmvxbCpmBuxzYJzq7VZZ26uNn9ybJ/zl8YGGtBu6DeMC2IjDZhrbf7z2EwD9Aa7YVaeixqbasCsPBcsNtaAcUFsrgHlBrlBb3hVrtM+t9kT6g3thn7DuGBuuCeUG+QGveGu3O7K7a7c7srtrtzuyv2u3O/K/a7c78r9rtzvyv2u3O/K/a7c78rjrjzuyuOuPO7K46487srjrjzuyuOuPK7Kehw3lBvkBr3BbvAb6g3thn7DXbnclctdudyVy1253JXLXbnclctdudyVy11Z7spyV5a7styV5a4sd2W5K8tdWe7KclfWu7LelfWurHdlvSvrXVnvynpX1rvy3DtUe8FstBPKDbNyn6A32A1+Q72h3fCq3OKfjwtmD55QbphR5xP0Brth/vNXM+psqzYLzrbqc1FnW3WZ8PrLff7l2VYn1BvaDf2GccFsq1EmlBvkBr3hVXlMxWyrE+oNr8pDJ/QbxgWzrU6YlefCzyYabcIM6mMu/eyZi8ZNs2texzGTZo4fc2wi/o+5wJH/J/miuigqT8foi8ZFdhyLyiJZFLsYmWSLYiejk2a9En9v3DR75aKySBbpIlvk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Vz3lVU951VNe9ZRXPeVVT3nVU171lFc95VVPedVTXvWUVz3lVU951VNejZRX48orD5bEmvh0teCauCU+XT14wFdGnXy6RrAk1sSW2BPXxC1xTzzgK6NOTt4zo2JC1DizSGMcziyKeVDjzKKLe+IBn1l0cUksiTWxJT69FlwTt8Q98YDPLLq4JJbEmtgSJ68lryWvJa8lryevJ68nryevJ68nryevJ68nrydvTd6avDV5a/LW5K3JW5O3Jm9N3pq8LXlb8rbkbcnbkrclb0velrwteVvy9uTtyduTtydvT96evD15e/L25O3JO5J3JO9I3pG8I3lH8o7kHck7kncsbzuOI3FJLIk1sSX2xDVxS9wTJ29J3pK8JXlL8pbkLclbkrckb0nekrySvJK8krySvJK8krySvJK8krySvJq8mryavJq8mryavJq8mryavJq8lryWvJa8lryWvJa8lryWvJa8lryevJ68nryevJ68nryevJ68nryevDV5a/LW5K3JW5O3Jm9N3pq8NXlr8rbkbcnbkrclb0velrwteVvytuRtyduTtyfvlVc9WBNb4tM1glvinnjAV0adXBJLYk1sieM3ztmj7Tgz6uKWuCcei8uZUReXxJJYE1tiT1wTt8Q9cfKW5C3JW5K3JG9J3pK8JXlL8pbkLckrySvJK8krySvJK8krySvJK8kryavJq8mryavJq8mryavJq8mryavJa8lryWvJa8lryWvJa8lryWvJa8nryevJ68nryevJ68nryevJ68nryVuTtyZvTd6avDV5a/LW5K3JW5O3Jm9L3pa8LXlb8rbkbcnbkrclb0velrw9eXvy9uTtyduTtydvT96evD15e/KO5B3JO5J3JO9I3pRXJeVVSXlVUl6VlFeS8kpSXknKK0l5JSmvJOWVpLySlFeS8kpSXknKK0l5JSmvJOWVpLySlFeS8kpSXknKK0l5JSmvJOWVpLySlFeS8kpSXknKK0l5JSmvJOWVpLySlFeS8kpSXknKK0l5JSmvJOWVpLySlFeS8kpSXknKK0l5JSmvJOWVpLySlFeS8kpSXknKK0l5JSmvJOWVpLySlFeS8kpSXknKK0l5JSmvJOWVpLySlFeS8kpSXknKK0l5JSmvJOWVpLySlFeS8kpSXknKK0l5JSmvJOWVpLySlFeS8kpSXknKK0l5JSmvJOWVpLyS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mrznfvMcz3O/efJ5rHuO7dnv59haWjZLy2Zp2Swtm6Vl87RsnpbN07J5WjZPY+LJ68nryevJ68lbk7cmb03emrw1eWvy1uStyVuTt6bt88qBk53xvHo2xjP1bEk9W1LPltSzJfVsST1bUs+W1LMl9WxJPVtSz5bUsyX1bEk9W1LPltSzJfVsST1bRvIOvOd0uptLYkmsa9zksMRjjaFcPduDWTZJPSupZyX1rKSeldSzknpWUs9K6llJPSupZyX1rKSeldSzknpWUs9K6llJPSupZyX1rGjyavKex7rnWJ378ZPP/fg5blfPxrilnpXUs5J6VlLPSupZST0rqWcl9ayknpXUs5J6VlLPSupZST0rqWcl9ayknpXUs5J6VlLPSupZqexTJPWsNPYp0tinSNrPSupZST0rqWcl9ayknpXUs5J6VlLPSupZST0rqWcl9ayknpXUs5J6VlLPSupZST0rqWcl7Wf1OBKTY3qQY5r2s5r2s5r2s5r2s5p6VlPPaupZTT2rqWc19aymntXUs5p6VlPPaupZTT2rqWc19aymnlVJY6JpTDSNiaYxsbRslpbN0rJZWjZLy5b2s5r2s5p6VlPPaupZTT2rqWc19aymntXUs5p6VlPPaupZdXpHPY1JpXe00jta07K1tGwtLVs6NtZ0bKzp2FjTsbGmY2NNx8aajo019aymntXUs5p6VlPPaupZTT2rnYzVTsbqIGN1kLGa+ktTf2naJ1raJ1raJ1raJ9qhiS2xJ66JW+KeOHlTz1rqWUs9a4V9sRVLzL7YhH2xpf6y1F+W+stSf1nqL0v7REv7REv7REv7REv7REv7REv7RNPk1eTV5FW2YbMjMX1tRl9b6i9L/WWpvyz1l6X+stRflvrLUn9Z2ida2ida2ida2ida2ida2idaTeurcmxvjWN7axzbW+ovS/1lqb8s9Zel/rLUX5b6y1J/WeovS/1lqb8s7RMt7ROtkznW0/oaZI4NMsdSf3nqL0/95am/PPWXp/7y1F+e+stTf3nqL0/95am//OqvGiyJ21p+v/ZfPTgtW9p/eeovT/3lqb889Zen/vLUX576y1N/eeovV3rf03miK73vRu972n952n952n952n952n952n956i9P/eWpvzz1l3taNmc798p27pXt3NPxoafjQ0/Hh57O6Tztvzztvzztvzztvzztv7ylZWtp2Xpatp6WLfWCp17w1Auejg89HR96Oj70dHzo6fjQR1qnIy3bYJ3Wg3VaUy/U1As19UJNvVBTL9TUCzX1Qk29UFMv1NQLNfVCTb1QUy/U1As19UJNvVBTL1QhQ2o6lqtKhlQlQ6qm5U/HcjUdy9V0LFfTsVw1xrYa67066/2az3O60n6hpv1CTfuFmvYLNR13XfN5LmafVSv7rJq225q225q229rYNmrabmtL20ZP20bK8Jq225qOkWo6RqrpGKmmY6SajpFqutZX0zlIS9f6WrrWd81vOf9OORIzDtd8EjvZE5/3JaPOuZ1c3BMP+MxMG8ExDn4EW2JPXBO3xD3xgM9tbL7Grl/zSS6WxJrYEnvimvj0SnBPPOBzm7y4JJbEmtgSny4Nbol74gGf2+rFJbEk1sSW2BMnb03eM7fnoz79mlty8rn9X1wSS2JNnNZpS+u0pXXa0jo983x+CqNfc0g8tsOzRy72xDVxS3wuf2yfZ7affGa7x3Z4ZvvFkljT37fEnrgmbomTd+A9X8d2c0ksiW399mteSvyWa/7JxQM++/TikjjVLJrY1m+85p9cXBO39Pd74vRbJP0WSb9FkleSVyyxJ66JO79d0m88j6Mu1sSWOI2VppqafsuVFfEbr6wItiNx+i2Wfoul32Lpt1j6LZa8lryWxtDSGHoaQ08uTy5PLk8uTy5PLk+ua782e+qaf3JxSSyJNbEl9sSndwS3xD3x+RvHf/3XP/3pb//2r3/+97/+29//5d//8Ze//Omf/3P9D//3T//83/7zT//nz//4y9///U///Pf/+Nvf/ulP/58//+0/4i/93//z57/Hn//+53+8/t+X+S9//5+vP18F/9df//aXSf/1T/zr4+N/2uOlsPGv+yupV4Fy/FiifFzC5mcMo4JZWwXaj/9ePv736vfyv66osABtPP4NY85HiArjdZv2w99gm2XQeTv1XIjXNYlVYoynFV53J+yq8EKnQvuhQv24Ql1rotY0Dn08LdDmdJlzVZa6Crwup/1QoG9+Q53v2T9/QyvtwxLj4xIST2RECXndmPywRNmsz9cNjnsoX/cxxoc1NmtjvjH4HszXsQujKfXHxdhsl04JLR+uj91CtLVlz/fEfrwQuw2zznkf54b5OiGhvfzHEr5ZqzYPKc+1+rp28mGJ7VJYWUth9aMSmwpzNv9VYU7e/ngsNptnjY/4nuM5cla5/lhjs31qvMrv/CVH/fCX7BajxdPO50953ef/cDGk/LGLIWvLmG/G+HgxdLNptCKr4VNy+o/buGxWbHzR+czentO7Pq+w+my+N/rjEnWXGEZiOIth5ccSbTMUh6yhOLx8vBibVeJ91XhdXBlpMeTHGpsNtMY3GM6N/EgB+nMN3QWo3VvG6z4kFY7xtQ1jfLhh7LdP7Wv79I/bZFvD17HFfKzrwxpqu8Gwe0Bfd5j9wyDfLkflt9S0Yn9Zjvp+DD9djCZfG9I6DoJ4M6TjzSM+O9495Nv+jFZ1/Yx8uPTTz9jtkpqs0XxdA/lwl2T69u7Z7O3tYr8U7+6eX+ef93DO+3Mfj0XbHUP3wTF0PubqP9bob++QbLy7Q9pWeLZD8vL2Dsnl/R2S6/s7JLf3d0ju7+6QHm8YH++QHm+f4h9vn9saatRoH9bw8fZP2ZXQ1owAbR+ebJb3z/WqvH+yV/UbTvZ2a6WtU2d9XYX7cK1U350893X2fBw17VB+bNla306v2t5Nr22FZ+lVx9vp1Y7306uV99Oryfvp1fTd9Hq8YXzc8rvtcz6+sbbPHw6ny/MaPu7FeF20/LhGa4+uc8lx2MfXqXbL0fpajtcV+o+X4/0T+V1sWFlD+jpe+XiH0Mv7R2/bxVgnKFbax8dN/f0T+f72iXx//0S+v38i37/hRL5/w4l8/4YT+fH2iXx//0T+cZu0+qXjJiv9Xq8mm3OD8f6l0PH+pdDxh14KfUXvSr92fHxZeGw30HUW/xqV/mGCjt1xaFnHsuU1th8m+W455gfA7+Ww8fFyxJtJ3ozy7XJ4WRfr69E2y6HvL8d266h1bR2pZX+rRKfEsA+vEx3bGF13xF6JKl+ssTbT14F5/7jG7qztZbh/zHzbhn6YguXYbqnilJF05euXMrv7Sr7yw9P18p/TtJTybiA/XYp0W+mXEvvx0GOl+quL+2Y8dkE01nW8Pnoe1J/u/e7vLsloK1M1Zfuvy7Lb2ura40pNW2z9nSXxxpL48M2S7LZZabpi8dhtJ4+XpZbdsmzLcMV38vhqmU7/WK/69TJOmSFfLqNKGd9sMbvbRkX7GmEd+rX19PQgrWzvPj0LhW2JdWIm25+y3W572m71q9tt9bTdVvvqKm7HOraw123wj8to+Ya1o/L22tmWeLh29gPL6rG22xPqbnttra4pBWlZ6m+U6LIO2bqNr5Vo60Z8bx+W2O/CbF2zm+8DKpvx2N2J0vtg/McSv3OIUopyiCL14wWx/XUAErZ9vNf45MiPU4vx8RHX7lZQ2hubinx4olV2t6SkrV2gtF4+vPtr/vYViXgl03uXJPYlnl2TKLt7Dw8vSpTdPaWnVyViiu+7lyWKf0eo+vuh+ngD2Uwx2G+oa1bRa0PVr9Xova90P44Pa/hu6p6vGyHV0znb79Xw8aTG/resG+uvfdbmt7x9/3Rf4mnTPf4pH28eu/tTY51qDdm07S5OVde1WfW6idNtkRWn5vrxxa+yu2b+8JZf2d6GeHjPr+zuLz2e4Vn7+3f99uPaV8f4UTYrZ3ej6tk2sqvwdM3sblM9XjPb+1RP10yzP3jN+GHHWjO7tmn1j+xel3Wi6a+rWZvF2GyqKmVNGxD1jw529yXW1VrVo39Uoh8PL8Lrh4fc29Egy/yVSF/LMq9jFel6fFxkd1PC1i7mla+rxOuY4qcS9vb1ou1SrG3U0jHMr0uxC9SjcZnnaGmvXX+nSB/rssoxDv/Sj1nnhX7shnR7iNrWBjI/4nB8uBzjO0ZkfMOIbLfUXtdJqua5o7+zuVdbZ+2vWwzHF4v0dTX+dRHAvlikHfeQ1FE2WTbq2ymyK/F0bze+4TmTMr7hSZN4SeofurergysqY7ObkWN3BDA/c7UGJc9P+2n++bFdkjXFbX7oabMku8sQra4d3g+b60/30uKNrR+v4nWG+Dok/fBOq+zuQBm7b9OjfHh/Il4Lu/k1yq+RTZHtBquc0lQrH581y+6il1amPecrq/o7S/K64bKWpLSPryPK7j7WqOsiwKilbn7OdpPVxim8dvlKTM9PadybbNskrGyfTyrr9q+WdNXr5+dYyvsXrKS8fcFqX+Lh0zDl/QtWUr7hgpXIN1ywEvmGC1Yib1+wer6BjM0Gst1QmT1Sqn6thvt9YPPaTdUv1lhzzr5eo6U4q+OLNWzN3G3+cY3tE1PPLr59UuPRxbf9b+my5id1a+/X8PK1GnWdC2jf/JbdQ1Olk+zDNt2/WxAr6+DZSrod/8uCvH9l9ZMa769cK+vZ09ex2fHxcuwiVXzdaZIUIL83qLK67nUC+/Gg7m5W2ZoNYG2zbm330P6x7om+dr6bo5Dtc0tM61GpfVNkdyVA12mAy8cHVdvxWKcjbsfH4/HZ4bumw/fy0eH745mWH56e/c7x4WZyhexuV0lfu8tev3ak6nXNUfK6mRYk2+eonq3c/ZnISpDXJVj/r6/cVa0uK0HqZgqs7B6kknUYk2fAmvzOdZHBTfNjfHzz/pMixNAx2keXecTf3lI/Ww7hUHf48bVrZw9/TH3/2uony/Hox+yf8Fgn7/PbAB+fd28fp3p2616qvX8mtPsxD8+EtiWevhegvX8mtLtX9fhMaPdI1eMzod2dpsdnQu3tKazPN5DNmdB+Q310635f49mte2n+/gHmvsazA8z9b3l0615295keNt22xNOme/xTPt48ds9VPbr5t01TXRXm25U/TtO+v/y/ptt5uvf3OgX/qcjusShdV+6HpltVvxbZheGxHtAfrzsimyK7a/fGpVAGVerPbzhp2/tubcVHGpHfKqKDy3X5KObXIrtE5ZqflxzL/XcWpK3LMaN9vCDbDc2cDa3LxxvakPcvlw/9hsvlw77hcvnuMavHh/67G00PD/33o/ro0H//yOx6MdwL9cO1u389x6OHgvYlHj0UpMf2nRSPHgr6pMajh4J0d5PqtWNRDqhKHR9uZHp8w9MrenzL0yt6vP30yidL8vTpFT2+4emV31iW3dMrn5R5+vTKJ2WePr3yaZlnT698Vubh0ytavuHple2yPG6B3Q2nxy8cK+3dk4p9iUcPWWx/ym908+6u1cNu3i/J427e3bV6+kzPJ0UeRsLzH7SNhH2Zx5GwL/M4Ej4r8zASPinzNBJ296CeR8J+50qVVzsfH4eCfsPjLJ8cszx5nEV1V+PZbKNtjfnx+zslj/7xu2A/23AfPhj3SZmnD8aptm/IbO1vZ/a2xHdk9tMH43R3C+fZg3H7Eo8ejPukxJMH4z47aHq6oR3f8gSm2nccHNj7Bwf2/sHB8S1PYOruGayHG9q2xLMNbV/i0ROYuwt9MrjCNvL7zp6/S3ToOlB6XdnSD2vo9t2AD09L9zWenZbubmk9f1eF+vZ50qfvqlDfXt168q4KrW+/POjpUmzeVfHJeDx9V4Xurik/PtWp3/AqS61vv8tyuxy/cZ5S29vnKfsleXyeUsc3nGI8X5btKca+zONTjH2Zx6cYn5V5eIrxSZmnpxi7G1WPTzG2DfBsX/zJOnp6kLMv8/ggp33HK9f7+2m7LfEtA/v0IGd73+vZQc62xLODnH2JR0fT+73P09dM6O4+0aPXTHxydPH0NRO6nTTz8Lx8f9S2jnPGKy0+PmobuxsBz+aZ6Pb2zLN5Jrq76fXslve+xLNb3jr87XkmOrZziJ7NM9HR3p9notu36T0NxO3zWc8C8fEGMjYbSHl7nsm+xrN5JrZ9NOvZPJNPajyaZ/LJb3k0z8SOtx9z2Zd42nSPf8rH7zY9tm+7ePKQ+S5NfX1FYvjmQxTbGlV5Gqv6F2us7WvU8fG3QazsLrc+e47KyvuzB628PXtwX+LZBmbl/dmDVr5h9qCVb5g9aPINswdN3p49+HwD2bySeL+hPnqOal/j2XNUn9R49BzVvsaz56g+qfHoOSqT/v4eal/j0R5q/1uePUf1vMbHz1Htazx7jsp2956ePke1XZCHz1GZvj/N9ZMa76/ch89RmW7nuDx7jmq/IM+eo7LdZ6yePUdltn339bPnqGz7MNbD56hsd7v22Xy7/Xg8eo5qv7fki28vts1xjL396qD9cjjHD745S7btV4ueTeu03aNYVtbUvx9enf/zlW/b3S8q6/7IXP6PV+72o2/PppeaP53QUsrHS7Ir8nSOqu2exnr+oJz59umyp2+G+J2l2bzWwXZXmYaPNUs8J/RvLsvzn/T2yy72JdLB1fi4xO4zV99Q4mEw1v2Z6l1i8zjldq083ujrN0zMtlrfH9L6/pDWt4e0+rdEwO6prO9fkl37794i+Lj96/ckWrO3239b4tmG1uofWuLhttre31Zt/6JrXkS6a//dDabHe9/9Mc2jhyr2G+rD1w89L6Kbltk9nPU4EXcPZz3cynYlHm5l2xIPdzLtG9bL4yK79bL78tXj9TLe3/mP93f+4+2d//5T2usqQpP+8TebbXuL6tkdOxvvf+DSxttfuNyXeHhtd7z/jUs/vuEjl358w1cu/fiGz1z68fZ3Lp9vIJtru/sN9dEdu32NZ3fsfPfmwIeXzD6p8eyS2f63PLpj5+V4t+n2JZ423eOf8vGnj4v+gdd2mqxf0lQ+nvnq5f33W/pu6rvbmqjmtuv83T2qpztK374w8NFe7pMBefaand2KUWfF+OY26Psf4Cvvf4DPZftV60eTmj+p8WhSs8turTx+1tZ3n6d6OvvWZTcF6vGsV9/dYno26/WTJXk669V1ezr1bNbrbyzLbtbrJ2Weznr9pMzTWa+flnk26/WzMg9nvfru/X9PZ71ul+VxC+g3TKxyfXti1b7Eo5mm25/yG928u3X1sJv3S/K4m3fvEXz6rO0nRR5GwvMftI2EfZnHkbAv8zgSPivzMBI+KfM0EnbvFXweCfud68Nnbd13cwSezul9/9Nx7vsPA67zne4ff5d6W6Qd6958O9Kc7V+L7F7L8+iTK5+UePLJFfftjdcnrwXcD+lYD9m13aPHvrt59HA5tnfBnj1G7bsnsJ5+tMHr9h2Yzz7a4HX/tN+jjzbsN1RZDwa8Lq/1zarZHqA0Eja9lUvspxipn+xJ18150U2R/fEfd/jT3flfirTt69rXIxtpRoxYf16iyvrUiYyPS2x/ivMmXU+TUH9zPB4O6vZbWEfra0s78vWs30lEWTflmvf68Ya2HdaVqrXqF9eM8Qpb+2qJtYOw+nGJ/U6Gr/KMuknE/v4X1/Y1jmPNmMyH4r/U2M5m4ZqYpgdkfwmi/g1fbfP+DV9t++yA8eFTeZ+UefpUnvdveMeF97ffcbEv8R3nSk+fyvPx9jsu9iUePZX3SYknT+V9drHi6Ya2L/N4Qxvf8I4LH2+/42Jf4tmG9snAPtzQ6vH2Oy72JR5taJ+UeLKhHe8fndXjW2bDHe8fndXt57DG+sRfKR/ufZ+WkC+WeHaMuC3x7BjxeP8I8Xj/+LAWef/4cD8ajw7t9iUeHdp9UuLJod1uFtzBXdty5AO79rhEOeoq8cPX6x6XKLyGX0q+hfRTibp72urhoeG+xrND1Lp71urpGXfdfvjq4eFl/eRW1KPDy+3KpVVUP94+qjycJZWCWJ5XUF1JrJY+ozl+anvZfgH7wYc8tq2yJkm8UiOdEepPrzffvi2wtXWbsrR+5DL6G2Ve/3JtZP1I0y1+KbN7X+CjFyR88nu4wTKnjrQv/571tvUXl7H5PfbuFchPSjy5Aln17c+1frqZrH1lL3nixi/jsfuCta8V/LpJ7x+uYR3vbiPbpbB18KF+fFxj98DVK4Y4Fut+bAZke9+qEEUlvwff61eLjG8oYvbVIl5WkTSd5dciu2nOvr5gK/ljyXb8PLDbV/Lz9dnRy6bI/px9RfQw/WoRdnojT8/5vSLGktTjO4r4psj2HeVrfyEtv3/m5yK7e1Xe1sVM73nn9zur2Gq7I9pa0S8WOcqdBa9/N744Jr42NvGxG5PdkvRjPdLay/jiwOavWcjxtSKvg/h1xmx2fMPPkd0qfpwnm1CquyLPpujW7bdoZH1e+HXw2DYLstmVt7ggdl7Cz3Psyk+HrnX7jEApHHimw5Kfl6NuT0yUExP7uMb+NZfrzKTMT6Z9/Gu2Dws3hrXtdjrPd8V5YH/eFe/uSjw9NmlvH79ul+LhsUnbvi2AV1KUXtPpya8Dsv22wHr2qlhJtzZH/Z1lSddoe22b46Tdo0+vy2fMC30dHn54iaS9/aLLT5aDTzm9OGX974zJONZDmC8em3OU7Xv+yroH9jorzseOP53I7j6Q9XBMtsshB/manvb5ZTn2Y1K4yvq6+nJsxmT3HJauya5ustnwd09A2WFr13X0zanf9lOOvfPKjnSVYfy8cnYPqDz85Ffd3Xh6+smv2rePUD/55Fcd+89hPPrk17bI009+1d374B5+8uuTBXn4ya/thpbeYpJfP/TLhrZ7GOLphra7d/V4Q9s+TvV0Qxv9/Q1tfMeGNt7f0Nr2maynG9r4ozc0WU93mGwuZrXdLSyXldAu48PD17Z7e35tTA5s6Q7BzweN+x+zHoYyaXXzY9o3/Jj+B/8YXY9UvbB9cYel6wznhfWLu05uZbmXj8Oo7W5l2VjXpG2of7VIXT8nX6f4zSKDIuOLRZwnM/2HM6Vfjl23hzbcki+vpD2+WkaZQD20fnlpfD1I/DqSl2MzMtuQHYTs6F87DOayyWtJ9OONv0l5907ytsSzO8nbHyPHMdY1oNc1pU3GyvacK80FV0k3QH/a7Wxvbz06pv9kOaQwJ+3jWxdNto9orwu5oxT5yjby2m8d3OSS/Hq0X4Z1+5F4Xlx1jPzkavnqsmj/uAGblrfP8Jtu78Ya51yH2aZ1dP944dr7zEcN9ctl1h75xXWz7e/eC/jsZtknJZ7cLGu7b2I9u1n2O+Oxy4LPynTKdP9ymTUor/Pzze6nbd8w+Gzt7Es8Wjumf/TayeNRjq+vnZbKlK/tjn8MlddF883a2d4LWZfHrB3yYahsbw8d6cbb4a7f8Yt8MxWg+faqUh9ccdcPf5G/ezn2k6V4dO+g+XZAxrrH9GKXzYDYu0dcny1JWsOj7VbN23P3tiWeHXHtf0zhNsac8rVJ2d3jWa8Lj8rxcLGPB3ZbJL1L9sXj7WOdUnbnLLvbXQ/vY7TdfZlnjbNdiodHOdsHtEqeIvU6qt0MSP3/58FfMd/kdO3fsHLG2yvn/QkwbXer6zUI3PQufmwOQXdvX9Mua0C65hurXy2STnh+q4gJL8jNJ+m/FvF3183+t7SDK6C7AXn7Ttd+OfIFUD2+uGLGaj0d9asrhpdaWmn+1bW7Zia/rh/ax0V2D2o9WrvbO3argOjIO6yfNpDtdbq2XsXio3487XP7kTE2D//hKt3Py1H/4CIP50i3vn2P+7PH59ruBtfT+c1te4vrG+Y3Kwc1P8xv/nlUdze4Hr3baruRqayTm3nWtlkMe3cxdhXc16xTrz/czpWfitT393Zj+xTheiCg/nioKb9RpPCMRvnh+u3PRcbb5+H7Ek/Ow/vx9ssEnq7bKj+cPstPy6Fvr9u+u6/1OhdZj6n98FrMXxZk93h2WWc07YeHTn4pstlSH04Q67sbWw8niPXdja2HE8T67otYjyeIfTKsa45nK719cd3ICqLXRe/65SLrrXLSji8XUYr0TQI8bZwfzhJ/WpLib19e6bsXDz46HPpkKR5dXum71/1VdWarFtkMx/aDmM+e8ezyDQ8DfrIkz57x7LuntZ49yfdJiSdP8u1/ysPnKz8Zj4eDunvx4NMnLPcH3mPd4as/Xjb+aWvdvXbwW4o8PGru+7cOPjtq7rt7WU+Pmvv2ZtbDo+b9AauuHYVq//jUquvbB6zbxbA1kUrN7GtneIX5DyXPf/hl9b77qeH9T3FJU7FsM6Kb7u3rfWI/zgb58b1m3bYzotfmoZbnD9vvFBnr85qan+T5tYi8e+j9SYlHh967dwM+O/TejoYd6zDEjrSl/zoa9f3RqO+PRv9jR6MwOa7kKVg/j8buRtHD0diXeDQaLn/waAwulNVNu7l9w0HM9h1Pjw5i9hk2Di5i5gmYvxPHr2FIF4brF4vwFnjLn8T4vUt/PA7lpX3x5/hYD3r68M2lne2nSh4egdRveO1Vr9/w2qtev+G1V/txpYjLD3e9f9pf1vpHHoHYcN7v8sMZ88+L0d9cjG2FpxtI+45D1PYdh6jtGw5Rt4dkbV3c6SkAfl2O7VuEnr3Ko+/uUT0fkfoHt4wpt9y8bk6G2u6Mqq7ZCPkKsfy0p2m7C6I9PXXguWd+OtvdPQb17GrIfjEGz6zbbjF2R5h1Xf5L8zvab4yGaeMbYXlq/C+L8fabL/bLYesl2K9TgLFZjvoNF3b6N7wF9JMleXhMtLtN9fCqzHY5nl6V2f+YhyMyvuG9V9v2753vyeQpkr/0f99eq14bifzwyuqff43/wUWe7jZ3t5ke7zZH/4adxP7jWA93m7uVw6eg8usmfh7Vsbtb9exwZruVrSdCe772/8tC7OZU8dRSuvLffmMz5V1gvelmIbYPC9p6vGCk+d6t/VRj+x2MZ88GjGP7bMB6SG/kb0nX3/gtQ3l8JH1K45ffsn0woFHkaOkYpP5WET608Mox+1qRvl7y/rpddvhXhkSIDznSw+k/D8nuw1jlKHyT6ig1B4j/VpmUzGWMr5dZu6tD0nNpv1mGm7wvrsemzC5auTH6Qtaz/vT1sk+KrCc6S368/Nci+x9U0w9qXx5eXVeMXqzy5TJpZWuaZPlLmd09p28q84onJgbn7ffnAZb9KR+PxqTLzr9XRHkZrx0fF+nb+710gEs+Dvby05LsNrpnH5obu9tOJuubKa8LYfkc5/ipyPaNls8+QD62N68ef3J76NufVP2dJdl8cnvsniZ5+sXcT5bl6TuGx/Yhqkef3N4uydOvCY7d9ZJnXxP8ZKt/9DXBz7KNN9gcWtvHoWRv3yD4pMSTGwTD3r5B8Nl4GDtB9frxeOyPd4YyrOPDd3t/VoTnLo7RPjx8s7dfj/nZcgg7rnxV/TfmF9ixvrNlP05T+innbf/i0rUgPc8Olh8vEYztnajOttpHvltanhexdvB6vvyY+S9F3r7lul+Ovl4HbT29rvzX5bA/djmYUG8jPfT063LUP3Q5/Mhvb7fNcvT3L6sN/4apPZ8sybPLamP3Yatnl9X2y/HwstonP+bhiNRv+NzQPgLyndP88reft5L67gTBbZyJraYR/+E7cP03itQ1JVZafs3Sz0XqH13k4eW9sbuh9fTy3mjf8Dr30b7hde77lVMab+vPTxr8PK67W1qPLvCN7dfTBqfTo334hfWxe+rqh6/Wt/Zxje2d1ydfWN+XePaF9dHff+557F4tWHh5Tjny5ItfFmT3Bp7OG3j65uPmY/dtrKef5hnbb2M9+jTP8w1kfLyB7DZUEZ4hkzST7eca229i+boWXX3Y15ajrPuuryXaLMfuDt+6xGJts33sHrl6fE1ilG+4JrG7m/Ub1ySGvn1N4jeWZHdNYncv6vE1if2yPL4msbun9fCaxLbEmk6mP+TIzyXG21cktpv8urfu+R2nP2/y285j1sTrouIXuzcfV6Vs/qnGeb37vfadF8p3R0TrCqmW8vGWWo5j+94f3vYvXb5cZf2gV8G+q/L2ZatPRvbRVrKf8aw8E59fpfl706aVGSlWPp42/TrQePc1LJ/MJ312ulmO7ZWrp5MW9rNSH83A2P6apzMw9kPy7MeUo7T3zxW3k/zLUfkM4w9Pch6/UcR07Sf8h0fjft7U9o9gfUeVh6dp5wHuu+dp89bk+ydq5ZBvmOD6yWo2bhW67cb23Rmu84bxN6ye7QssmcTwapmx+TXbKs4balzrF6to6ey+fngj529VkXWqpPLD9MHfqnLwZTOpZVNldz+rNFtvmnqxfHSlcl/l4dfv5l2I3RHoszmz897Od/Th9pbWwz78dPs/2P79q5tuXx9K0/zlm1+r2PENq8i+I2/tW/LWviVvzf7w9SyMrWwjand763krbr+npTxAV3W3ze2e1tLGcXrPbzfxn/N/e4/r2VyG107qGy4czEtX7185ON9B9v5J8quOvnuW/NmyPL148KrzDVcPPtt4+ULQi7t8vPF+0gKaWqB8WMXfftTwt0Z3c5HodVB9vHuVaL8sTydplGP7da2Hp7v7hn40TWP/gq+DtXNI/grNb72vbB2IvYp8/PK115BsP5G3vm4nLZ+a/VYV5cbIC/tXqxiPtuSz7997eRpvzJ0Py24WZfc417Nn2/bL0f6fH+b5fyzH7s0Wjz5L/0mNR9+l/6zGkw/Tf7J6pRz/rzOH39xIhANKObbj2t6dm/BZjSdTnOYk6/dzej8iym/xr4/rmp2kUuuXq6RleaNKZx33L8eJrjcHaP5cye9WWVNy3qqyLjupvhGQvOsqX03/JSA/ef9v/npZ/+izcPt3IvN2uKofXlncl3j2yPy+xJPrm59892FdRx/5PXe/9emIJ4+H7D/q8Wws5O1pQZ98QYYP0h1t97GVbZGVAH7Y+GIRnk+b36X66pKs2zW++wr4J0XWNWfff19v96Zd45tHu9cx/0YR+2oRnpe1oV8tsj7m+KpXv1jEea+Ll68OLO/9MdevfpHK1xWdV73d2tlOQlE+o5G/wfbThyXn6wXfPiz5pMajw5JS3n5l5n5A1Hh/cK2bASnbj2/zFtJ8c/E3lsPW826v9WK75dhsIw8/wfYqsttdPf0G2+7neOEivpQPf84nRdYDZq+Lf/WrRdbjma970duBHW+f4OxrPDvB+aTGkxOcT7636zwlUN0/bl95+5VZny6IpAX5eERk+1HYJnyZufnH6VqKbO8jpBe8v84JtnX6w4RNcziG/FaRg+/pNPm4yO6JoSHrQurIL+H9+ZmSUnT7Lbj7EoPnhweH/86SPPwW6qvK7oGuhx9DfVXZvk7wyddQS9H91+AefQ51X+Xp91BfVXZf3Xz2QdTPFuXZF1E/baF1sPRpC+3rMIFZat/V2X0c6+G7n0vZvl7w2cufS9ndAnv49udXkd30lKevf/4sdQu3elw+St3j3ezfPlW5bmSUmq4J//wM77bEOm4r+WT0d0r0tZW98GtLMdIXKtMV8t8oIcz0eWH/0lLEtxyuH3J87Yf0dYZSun7phxRZ8+xLvm76OyV0vdu02PG1ErYOPF8dKV8rwXsNzMbXSqwHwkqebvhzidfB/Hg72reTDXl1laaDkdcFuuclmEiTX1315RL9SyXsSLMmjy+V4Gjzhfq1Ekzk8fq1H8JzAurp5Uq/U6IW5g3Yl9ZIGZ5eh1w/LPE6T9xdohXj9Uz1wxPF7XLwad4xvrRaX0fK61jhONrXSsi69Xto/WIJpUR7u4R9dSnSZyLL10o4Y5GnfX9xKfqXGu3hpxRKae9+1O39B7ZK+Y4ntl5Vtm9xKZwqH6Xmhy2On+tsjkP7WBPU+uiyq7KdJ+28nMl85G/u/XyCurui+ToJWAcdeuQgG19emlq2S/PJ7G/q6G72Rtl9O+vZh+I+W5aqzM6vOr78mzofuLde9Y06Tp0hX6+zpojNmrsx3j3R9TpQ5JPuQ7+45QxO40ftfdMNu2e6nj4J+aqy/fTbk0chP6nBm5G+PCa/8WvGN/ya8cf+mte9qMbNqM3jR/El0jd/zb7Gd/+avCS/9uB+X0LzvFbx8fF2L9t3FpoRLe3r6V09pXe1LydL4y0t1vzYrevxDdt/zBJ6d4vZ1viGLeY1orzq7zVCuvs9+vbtj32NZ7c/Pqnx4e2P//76L3/+17/+41/+9m//+ud//+u//f3/vv7df81S//jrn//H3/5y/df/9R9//9f0//77//f/3P/P//jHX//2t7/+73/5P//4t3/9y//8j3/8ZVaa/9+fjus//pu0av/0usUm//2f/lRe/72/Lhv9U+99vP67vv67+uvw6nVyWef/X85/UP5pvtviv//XXML/Hw=="
2487
2487
  }
2488
2488
  ],
2489
2489
  "outputs": {
@@ -3659,215 +3659,215 @@
3659
3659
  },
3660
3660
  {
3661
3661
  "name": "Field::to_le_bits",
3662
- "start": 1192
3662
+ "start": 1196
3663
3663
  },
3664
3664
  {
3665
3665
  "name": "Field::to_be_bits",
3666
- "start": 2384
3666
+ "start": 2387
3667
3667
  },
3668
3668
  {
3669
3669
  "name": "Field::to_le_bytes",
3670
- "start": 3564
3670
+ "start": 3562
3671
3671
  },
3672
3672
  {
3673
3673
  "name": "Field::to_be_bytes",
3674
- "start": 5035
3674
+ "start": 5033
3675
3675
  },
3676
3676
  {
3677
3677
  "name": "Field::to_le_radix",
3678
- "start": 5906
3678
+ "start": 5904
3679
3679
  },
3680
3680
  {
3681
3681
  "name": "Field::to_be_radix",
3682
- "start": 6364
3682
+ "start": 6362
3683
3683
  },
3684
3684
  {
3685
3685
  "name": "Field::pow_32",
3686
- "start": 7055
3686
+ "start": 7053
3687
3687
  },
3688
3688
  {
3689
3689
  "name": "Field::sgn0",
3690
- "start": 7446
3690
+ "start": 7455
3691
3691
  },
3692
3692
  {
3693
3693
  "name": "Field::lt",
3694
- "start": 7518
3694
+ "start": 7538
3695
3695
  },
3696
3696
  {
3697
3697
  "name": "Field::from_le_bytes",
3698
- "start": 7898
3698
+ "start": 7918
3699
3699
  },
3700
3700
  {
3701
3701
  "name": "Field::from_be_bytes",
3702
- "start": 8456
3702
+ "start": 8476
3703
3703
  },
3704
3704
  {
3705
3705
  "name": "__assert_max_bit_size",
3706
- "start": 8737
3706
+ "start": 8757
3707
3707
  },
3708
3708
  {
3709
3709
  "name": "__to_le_radix",
3710
- "start": 8865
3710
+ "start": 8885
3711
3711
  },
3712
3712
  {
3713
3713
  "name": "__to_be_radix",
3714
- "start": 8993
3714
+ "start": 9013
3715
3715
  },
3716
3716
  {
3717
3717
  "name": "__to_le_bits",
3718
- "start": 9710
3718
+ "start": 9734
3719
3719
  },
3720
3720
  {
3721
3721
  "name": "__to_be_bits",
3722
- "start": 10424
3722
+ "start": 10452
3723
3723
  },
3724
3724
  {
3725
3725
  "name": "modulus_num_bits",
3726
- "start": 10499
3726
+ "start": 10527
3727
3727
  },
3728
3728
  {
3729
3729
  "name": "modulus_be_bits",
3730
- "start": 10573
3730
+ "start": 10603
3731
3731
  },
3732
3732
  {
3733
3733
  "name": "modulus_le_bits",
3734
- "start": 10647
3734
+ "start": 10679
3735
3735
  },
3736
3736
  {
3737
3737
  "name": "modulus_be_bytes",
3738
- "start": 10723
3738
+ "start": 10755
3739
3739
  },
3740
3740
  {
3741
3741
  "name": "modulus_le_bytes",
3742
- "start": 10799
3742
+ "start": 10831
3743
3743
  },
3744
3744
  {
3745
3745
  "name": "__field_less_than",
3746
- "start": 10960
3746
+ "start": 10992
3747
3747
  },
3748
3748
  {
3749
3749
  "name": "field_less_than",
3750
- "start": 11036
3750
+ "start": 11068
3751
3751
  },
3752
3752
  {
3753
3753
  "name": "bytes32_to_field",
3754
- "start": 11178
3754
+ "start": 11210
3755
3755
  },
3756
3756
  {
3757
3757
  "name": "lt_fallback",
3758
- "start": 11585
3758
+ "start": 11617
3759
3759
  },
3760
3760
  {
3761
3761
  "name": "tests::test_to_be_bits",
3762
- "start": 12547
3762
+ "start": 12579
3763
3763
  },
3764
3764
  {
3765
3765
  "name": "tests::test_to_le_bits",
3766
- "start": 12787
3766
+ "start": 12852
3767
3767
  },
3768
3768
  {
3769
3769
  "name": "tests::test_to_be_bytes",
3770
- "start": 13029
3770
+ "start": 13127
3771
3771
  },
3772
3772
  {
3773
3773
  "name": "tests::test_to_le_bytes",
3774
- "start": 13335
3774
+ "start": 13433
3775
3775
  },
3776
3776
  {
3777
3777
  "name": "tests::test_to_be_radix",
3778
- "start": 13641
3778
+ "start": 13739
3779
3779
  },
3780
3780
  {
3781
3781
  "name": "tests::test_to_le_radix",
3782
- "start": 14223
3782
+ "start": 14321
3783
3783
  },
3784
3784
  {
3785
3785
  "name": "tests::test_to_le_radix_1",
3786
- "start": 14823
3786
+ "start": 14921
3787
3787
  },
3788
3788
  {
3789
3789
  "name": "tests::test_to_le_radix_brillig_1",
3790
- "start": 15276
3790
+ "start": 15374
3791
3791
  },
3792
3792
  {
3793
3793
  "name": "tests::test_to_le_radix_3",
3794
- "start": 15630
3794
+ "start": 15728
3795
3795
  },
3796
3796
  {
3797
3797
  "name": "tests::test_to_le_radix_brillig_3",
3798
- "start": 15941
3798
+ "start": 16039
3799
3799
  },
3800
3800
  {
3801
3801
  "name": "tests::test_to_le_radix_512",
3802
- "start": 16369
3802
+ "start": 16467
3803
3803
  },
3804
3804
  {
3805
3805
  "name": "tests::not_enough_limbs_brillig",
3806
- "start": 16778
3806
+ "start": 16876
3807
3807
  },
3808
3808
  {
3809
3809
  "name": "tests::not_enough_limbs",
3810
- "start": 16974
3810
+ "start": 17072
3811
3811
  },
3812
3812
  {
3813
3813
  "name": "tests::test_field_less_than",
3814
- "start": 17116
3814
+ "start": 17214
3815
3815
  },
3816
3816
  {
3817
3817
  "name": "tests::test_large_field_values_unconstrained",
3818
- "start": 17371
3818
+ "start": 17469
3819
3819
  },
3820
3820
  {
3821
3821
  "name": "tests::test_large_field_values",
3822
- "start": 17819
3822
+ "start": 17922
3823
3823
  },
3824
3824
  {
3825
3825
  "name": "tests::test_decomposition_edge_cases",
3826
- "start": 18261
3826
+ "start": 18369
3827
3827
  },
3828
3828
  {
3829
3829
  "name": "tests::test_pow_32",
3830
- "start": 18775
3830
+ "start": 18959
3831
3831
  },
3832
3832
  {
3833
3833
  "name": "tests::test_sgn0",
3834
- "start": 19104
3834
+ "start": 19288
3835
3835
  },
3836
3836
  {
3837
3837
  "name": "tests::test_bit_decomposition_overflow",
3838
- "start": 19498
3838
+ "start": 19710
3839
3839
  },
3840
3840
  {
3841
3841
  "name": "tests::test_byte_decomposition_overflow",
3842
- "start": 19778
3842
+ "start": 19992
3843
3843
  },
3844
3844
  {
3845
3845
  "name": "tests::test_to_from_be_bytes_bn254_edge_cases",
3846
- "start": 19995
3846
+ "start": 20209
3847
3847
  },
3848
3848
  {
3849
3849
  "name": "tests::test_to_from_le_bytes_bn254_edge_cases",
3850
- "start": 21946
3850
+ "start": 22160
3851
3851
  },
3852
3852
  {
3853
3853
  "name": "tests::from_le_bits",
3854
- "start": 24029
3854
+ "start": 24245
3855
3855
  },
3856
3856
  {
3857
3857
  "name": "tests::from_be_bits",
3858
- "start": 24574
3858
+ "start": 24792
3859
3859
  },
3860
3860
  {
3861
3861
  "name": "tests::test_to_from_be_bits_bn254_edge_cases",
3862
- "start": 24820
3862
+ "start": 25038
3863
3863
  },
3864
3864
  {
3865
3865
  "name": "tests::test_to_from_le_bits_bn254_edge_cases",
3866
- "start": 26734
3866
+ "start": 26971
3867
3867
  }
3868
3868
  ],
3869
3869
  "path": "std/field/mod.nr",
3870
- "source": "pub mod bn254;\nuse crate::{runtime::is_unconstrained, static_assert};\nuse bn254::lt as bn254_lt;\n\nimpl Field {\n /// Asserts that `self` can be represented in `bit_size` bits.\n ///\n /// # Failures\n /// Causes a constraint failure for `Field` values exceeding `2^{bit_size}`.\n // docs:start:assert_max_bit_size\n pub fn assert_max_bit_size<let BIT_SIZE: u32>(self) {\n // docs:end:assert_max_bit_size\n static_assert(\n BIT_SIZE < modulus_num_bits() as u32,\n \"BIT_SIZE must be less than modulus_num_bits\",\n );\n __assert_max_bit_size(self, BIT_SIZE);\n }\n\n /// Decomposes `self` into its little endian bit decomposition as a `[u1; N]` array.\n /// This array will be zero padded should not all bits be necessary to represent `self`.\n ///\n /// # Failures\n /// Causes a constraint failure for `Field` values exceeding `2^N` as the resulting array will not\n /// be able to represent the original `Field`.\n ///\n /// # Safety\n /// The bit decomposition returned is canonical and is guaranteed to not overflow the modulus.\n // docs:start:to_le_bits\n pub fn to_le_bits<let N: u32>(self: Self) -> [u1; N] {\n // docs:end:to_le_bits\n let bits = __to_le_bits(self);\n\n if !is_unconstrained() {\n // Ensure that the byte decomposition does not overflow the modulus\n let p = modulus_le_bits();\n assert(bits.len() <= p.len());\n let mut ok = bits.len() != p.len();\n for i in 0..N {\n if !ok {\n if (bits[N - 1 - i] != p[N - 1 - i]) {\n assert(p[N - 1 - i] == 1);\n ok = true;\n }\n }\n }\n assert(ok);\n }\n bits\n }\n\n /// Decomposes `self` into its big endian bit decomposition as a `[u1; N]` array.\n /// This array will be zero padded should not all bits be necessary to represent `self`.\n ///\n /// # Failures\n /// Causes a constraint failure for `Field` values exceeding `2^N` as the resulting array will not\n /// be able to represent the original `Field`.\n ///\n /// # Safety\n /// The bit decomposition returned is canonical and is guaranteed to not overflow the modulus.\n // docs:start:to_be_bits\n pub fn to_be_bits<let N: u32>(self: Self) -> [u1; N] {\n // docs:end:to_be_bits\n let bits = __to_be_bits(self);\n\n if !is_unconstrained() {\n // Ensure that the decomposition does not overflow the modulus\n let p = modulus_be_bits();\n assert(bits.len() <= p.len());\n let mut ok = bits.len() != p.len();\n for i in 0..N {\n if !ok {\n if (bits[i] != p[i]) {\n assert(p[i] == 1);\n ok = true;\n }\n }\n }\n assert(ok);\n }\n bits\n }\n\n /// Decomposes `self` into its little endian byte decomposition as a `[u8;N]` array\n /// This array will be zero padded should not all bytes be necessary to represent `self`.\n ///\n /// # Failures\n /// The length N of the array must be big enough to contain all the bytes of the 'self',\n /// and no more than the number of bytes required to represent the field modulus\n ///\n /// # Safety\n /// The result is ensured to be the canonical decomposition of the field element\n // docs:start:to_le_bytes\n pub fn to_le_bytes<let N: u32>(self: Self) -> [u8; N] {\n // docs:end:to_le_bytes\n static_assert(\n N <= modulus_le_bytes().len(),\n \"N must be less than or equal to modulus_le_bytes().len()\",\n );\n // Compute the byte decomposition\n let bytes = self.to_le_radix(256);\n\n if !is_unconstrained() {\n // Ensure that the byte decomposition does not overflow the modulus\n let p = modulus_le_bytes();\n assert(bytes.len() <= p.len());\n let mut ok = bytes.len() != p.len();\n for i in 0..N {\n if !ok {\n if (bytes[N - 1 - i] != p[N - 1 - i]) {\n assert(bytes[N - 1 - i] < p[N - 1 - i]);\n ok = true;\n }\n }\n }\n assert(ok);\n }\n bytes\n }\n\n /// Decomposes `self` into its big endian byte decomposition as a `[u8;N]` array of length required to represent the field modulus\n /// This array will be zero padded should not all bytes be necessary to represent `self`.\n ///\n /// # Failures\n /// The length N of the array must be big enough to contain all the bytes of the 'self',\n /// and no more than the number of bytes required to represent the field modulus\n ///\n /// # Safety\n /// The result is ensured to be the canonical decomposition of the field element\n // docs:start:to_be_bytes\n pub fn to_be_bytes<let N: u32>(self: Self) -> [u8; N] {\n // docs:end:to_be_bytes\n static_assert(\n N <= modulus_le_bytes().len(),\n \"N must be less than or equal to modulus_le_bytes().len()\",\n );\n // Compute the byte decomposition\n let bytes = self.to_be_radix(256);\n\n if !is_unconstrained() {\n // Ensure that the byte decomposition does not overflow the modulus\n let p = modulus_be_bytes();\n assert(bytes.len() <= p.len());\n let mut ok = bytes.len() != p.len();\n for i in 0..N {\n if !ok {\n if (bytes[i] != p[i]) {\n assert(bytes[i] < p[i]);\n ok = true;\n }\n }\n }\n assert(ok);\n }\n bytes\n }\n\n fn to_le_radix<let N: u32>(self: Self, radix: u32) -> [u8; N] {\n // Brillig does not need an immediate radix\n if !crate::runtime::is_unconstrained() {\n static_assert(1 < radix, \"radix must be greater than 1\");\n static_assert(radix <= 256, \"radix must be less than or equal to 256\");\n static_assert(radix & (radix - 1) == 0, \"radix must be a power of 2\");\n }\n __to_le_radix(self, radix)\n }\n\n fn to_be_radix<let N: u32>(self: Self, radix: u32) -> [u8; N] {\n // Brillig does not need an immediate radix\n if !crate::runtime::is_unconstrained() {\n static_assert(1 < radix, \"radix must be greater than 1\");\n static_assert(radix <= 256, \"radix must be less than or equal to 256\");\n static_assert(radix & (radix - 1) == 0, \"radix must be a power of 2\");\n }\n __to_be_radix(self, radix)\n }\n\n // Returns self to the power of the given exponent value.\n // Caution: we assume the exponent fits into 32 bits\n // using a bigger bit size impacts negatively the performance and should be done only if the exponent does not fit in 32 bits\n pub fn pow_32(self, exponent: Field) -> Field {\n let mut r: Field = 1;\n let b: [u1; 32] = exponent.to_le_bits();\n\n for i in 1..33 {\n r *= r;\n r = (b[32 - i] as Field) * (r * self) + (1 - b[32 - i] as Field) * r;\n }\n r\n }\n\n // Parity of (prime) Field element, i.e. sgn0(x mod p) = 0 if x `elem` {0, ..., p-1} is even, otherwise sgn0(x mod p) = 1.\n pub fn sgn0(self) -> u1 {\n self as u1\n }\n\n pub fn lt(self, another: Field) -> bool {\n if crate::compat::is_bn254() {\n bn254_lt(self, another)\n } else {\n lt_fallback(self, another)\n }\n }\n\n /// Convert a little endian byte array to a field element.\n /// If the provided byte array overflows the field modulus then the Field will silently wrap around.\n pub fn from_le_bytes<let N: u32>(bytes: [u8; N]) -> Field {\n static_assert(\n N <= modulus_le_bytes().len(),\n \"N must be less than or equal to modulus_le_bytes().len()\",\n );\n let mut v = 1;\n let mut result = 0;\n\n for i in 0..N {\n result += (bytes[i] as Field) * v;\n v = v * 256;\n }\n result\n }\n\n /// Convert a big endian byte array to a field element.\n /// If the provided byte array overflows the field modulus then the Field will silently wrap around.\n pub fn from_be_bytes<let N: u32>(bytes: [u8; N]) -> Field {\n let mut v = 1;\n let mut result = 0;\n\n for i in 0..N {\n result += (bytes[N - 1 - i] as Field) * v;\n v = v * 256;\n }\n result\n }\n}\n\n#[builtin(apply_range_constraint)]\nfn __assert_max_bit_size(value: Field, bit_size: u32) {}\n\n// `_radix` must be less than 256\n#[builtin(to_le_radix)]\nfn __to_le_radix<let N: u32>(value: Field, radix: u32) -> [u8; N] {}\n\n// `_radix` must be less than 256\n#[builtin(to_be_radix)]\nfn __to_be_radix<let N: u32>(value: Field, radix: u32) -> [u8; N] {}\n\n/// Decomposes `self` into its little endian bit decomposition as a `[u1; N]` array.\n/// This array will be zero padded should not all bits be necessary to represent `self`.\n///\n/// # Failures\n/// Causes a constraint failure for `Field` values exceeding `2^N` as the resulting array will not\n/// be able to represent the original `Field`.\n///\n/// # Safety\n/// Values of `N` equal to or greater than the number of bits necessary to represent the `Field` modulus\n/// (e.g. 254 for the BN254 field) allow for multiple bit decompositions. This is due to how the `Field` will\n/// wrap around due to overflow when verifying the decomposition.\n#[builtin(to_le_bits)]\nfn __to_le_bits<let N: u32>(value: Field) -> [u1; N] {}\n\n/// Decomposes `self` into its big endian bit decomposition as a `[u1; N]` array.\n/// This array will be zero padded should not all bits be necessary to represent `self`.\n///\n/// # Failures\n/// Causes a constraint failure for `Field` values exceeding `2^N` as the resulting array will not\n/// be able to represent the original `Field`.\n///\n/// # Safety\n/// Values of `N` equal to or greater than the number of bits necessary to represent the `Field` modulus\n/// (e.g. 254 for the BN254 field) allow for multiple bit decompositions. This is due to how the `Field` will\n/// wrap around due to overflow when verifying the decomposition.\n#[builtin(to_be_bits)]\nfn __to_be_bits<let N: u32>(value: Field) -> [u1; N] {}\n\n#[builtin(modulus_num_bits)]\npub comptime fn modulus_num_bits() -> u64 {}\n\n#[builtin(modulus_be_bits)]\npub comptime fn modulus_be_bits() -> [u1] {}\n\n#[builtin(modulus_le_bits)]\npub comptime fn modulus_le_bits() -> [u1] {}\n\n#[builtin(modulus_be_bytes)]\npub comptime fn modulus_be_bytes() -> [u8] {}\n\n#[builtin(modulus_le_bytes)]\npub comptime fn modulus_le_bytes() -> [u8] {}\n\n/// An unconstrained only built in to efficiently compare fields.\n#[builtin(field_less_than)]\nunconstrained fn __field_less_than(x: Field, y: Field) -> bool {}\n\npub(crate) unconstrained fn field_less_than(x: Field, y: Field) -> bool {\n __field_less_than(x, y)\n}\n\n// Convert a 32 byte array to a field element by modding\npub fn bytes32_to_field(bytes32: [u8; 32]) -> Field {\n // Convert it to a field element\n let mut v = 1;\n let mut high = 0 as Field;\n let mut low = 0 as Field;\n\n for i in 0..16 {\n high = high + (bytes32[15 - i] as Field) * v;\n low = low + (bytes32[16 + 15 - i] as Field) * v;\n v = v * 256;\n }\n // Abuse that a % p + b % p = (a + b) % p and that low < p\n low + high * v\n}\n\nfn lt_fallback(x: Field, y: Field) -> bool {\n if is_unconstrained() {\n // Safety: unconstrained context\n unsafe {\n field_less_than(x, y)\n }\n } else {\n let x_bytes: [u8; 32] = x.to_le_bytes();\n let y_bytes: [u8; 32] = y.to_le_bytes();\n let mut x_is_lt = false;\n let mut done = false;\n for i in 0..32 {\n if (!done) {\n let x_byte = x_bytes[32 - 1 - i] as u8;\n let y_byte = y_bytes[32 - 1 - i] as u8;\n let bytes_match = x_byte == y_byte;\n if !bytes_match {\n x_is_lt = x_byte < y_byte;\n done = true;\n }\n }\n }\n x_is_lt\n }\n}\n\nmod tests {\n use crate::{panic::panic, runtime, static_assert};\n use super::{\n field_less_than, modulus_be_bits, modulus_be_bytes, modulus_le_bits, modulus_le_bytes,\n };\n\n #[test]\n // docs:start:to_be_bits_example\n fn test_to_be_bits() {\n let field = 2;\n let bits: [u1; 8] = field.to_be_bits();\n assert_eq(bits, [0, 0, 0, 0, 0, 0, 1, 0]);\n }\n // docs:end:to_be_bits_example\n\n #[test]\n // docs:start:to_le_bits_example\n fn test_to_le_bits() {\n let field = 2;\n let bits: [u1; 8] = field.to_le_bits();\n assert_eq(bits, [0, 1, 0, 0, 0, 0, 0, 0]);\n }\n // docs:end:to_le_bits_example\n\n #[test]\n // docs:start:to_be_bytes_example\n fn test_to_be_bytes() {\n let field = 2;\n let bytes: [u8; 8] = field.to_be_bytes();\n assert_eq(bytes, [0, 0, 0, 0, 0, 0, 0, 2]);\n assert_eq(Field::from_be_bytes::<8>(bytes), field);\n }\n // docs:end:to_be_bytes_example\n\n #[test]\n // docs:start:to_le_bytes_example\n fn test_to_le_bytes() {\n let field = 2;\n let bytes: [u8; 8] = field.to_le_bytes();\n assert_eq(bytes, [2, 0, 0, 0, 0, 0, 0, 0]);\n assert_eq(Field::from_le_bytes::<8>(bytes), field);\n }\n // docs:end:to_le_bytes_example\n\n #[test]\n // docs:start:to_be_radix_example\n fn test_to_be_radix() {\n // 259, in base 256, big endian, is [1, 3].\n // i.e. 3 * 256^0 + 1 * 256^1\n let field = 259;\n\n // The radix (in this example, 256) must be a power of 2.\n // The length of the returned byte array can be specified to be\n // >= the amount of space needed.\n let bytes: [u8; 8] = field.to_be_radix(256);\n assert_eq(bytes, [0, 0, 0, 0, 0, 0, 1, 3]);\n assert_eq(Field::from_be_bytes::<8>(bytes), field);\n }\n // docs:end:to_be_radix_example\n\n #[test]\n // docs:start:to_le_radix_example\n fn test_to_le_radix() {\n // 259, in base 256, little endian, is [3, 1].\n // i.e. 3 * 256^0 + 1 * 256^1\n let field = 259;\n\n // The radix (in this example, 256) must be a power of 2.\n // The length of the returned byte array can be specified to be\n // >= the amount of space needed.\n let bytes: [u8; 8] = field.to_le_radix(256);\n assert_eq(bytes, [3, 1, 0, 0, 0, 0, 0, 0]);\n assert_eq(Field::from_le_bytes::<8>(bytes), field);\n }\n // docs:end:to_le_radix_example\n\n #[test(should_fail_with = \"radix must be greater than 1\")]\n fn test_to_le_radix_1() {\n // this test should only fail in constrained mode\n if !runtime::is_unconstrained() {\n let field = 2;\n let _: [u8; 8] = field.to_le_radix(1);\n } else {\n panic(\"radix must be greater than 1\");\n }\n }\n\n // Updated test to account for Brillig restriction that radix must be greater than 2\n #[test(should_fail_with = \"radix must be greater than 1\")]\n fn test_to_le_radix_brillig_1() {\n // this test should only fail in constrained mode\n if !runtime::is_unconstrained() {\n let field = 1;\n let _: [u8; 8] = field.to_le_radix(1);\n } else {\n panic(\"radix must be greater than 1\");\n }\n }\n\n #[test(should_fail_with = \"radix must be a power of 2\")]\n fn test_to_le_radix_3() {\n // this test should only fail in constrained mode\n if !runtime::is_unconstrained() {\n let field = 2;\n let _: [u8; 8] = field.to_le_radix(3);\n } else {\n panic(\"radix must be a power of 2\");\n }\n }\n\n #[test]\n fn test_to_le_radix_brillig_3() {\n // this test should only fail in constrained mode\n if runtime::is_unconstrained() {\n let field = 1;\n let out: [u8; 8] = field.to_le_radix(3);\n let mut expected = [0; 8];\n expected[0] = 1;\n assert(out == expected, \"unexpected result\");\n }\n }\n\n #[test(should_fail_with = \"radix must be less than or equal to 256\")]\n fn test_to_le_radix_512() {\n // this test should only fail in constrained mode\n if !runtime::is_unconstrained() {\n let field = 2;\n let _: [u8; 8] = field.to_le_radix(512);\n } else {\n panic(\"radix must be less than or equal to 256\")\n }\n }\n\n #[test(should_fail_with = \"Field failed to decompose into specified 16 limbs\")]\n unconstrained fn not_enough_limbs_brillig() {\n let _: [u8; 16] = 0x100000000000000000000000000000000.to_le_bytes();\n }\n\n #[test(should_fail_with = \"Field failed to decompose into specified 16 limbs\")]\n fn not_enough_limbs() {\n let _: [u8; 16] = 0x100000000000000000000000000000000.to_le_bytes();\n }\n\n #[test]\n unconstrained fn test_field_less_than() {\n assert(field_less_than(0, 1));\n assert(field_less_than(0, 0x100));\n assert(field_less_than(0x100, 0 - 1));\n assert(!field_less_than(0 - 1, 0));\n }\n\n #[test]\n unconstrained fn test_large_field_values_unconstrained() {\n let large_field = 0xffffffffffffffff;\n\n let bits: [u1; 64] = large_field.to_le_bits();\n assert_eq(bits[0], 1);\n\n let bytes: [u8; 8] = large_field.to_le_bytes();\n assert_eq(Field::from_le_bytes::<8>(bytes), large_field);\n\n let radix_bytes: [u8; 8] = large_field.to_le_radix(256);\n assert_eq(Field::from_le_bytes::<8>(radix_bytes), large_field);\n }\n\n #[test]\n fn test_large_field_values() {\n let large_val = 0xffffffffffffffff;\n\n let bits: [u1; 64] = large_val.to_le_bits();\n assert_eq(bits[0], 1);\n\n let bytes: [u8; 8] = large_val.to_le_bytes();\n assert_eq(Field::from_le_bytes::<8>(bytes), large_val);\n\n let radix_bytes: [u8; 8] = large_val.to_le_radix(256);\n assert_eq(Field::from_le_bytes::<8>(radix_bytes), large_val);\n }\n\n #[test]\n fn test_decomposition_edge_cases() {\n let zero_bits: [u1; 8] = 0.to_le_bits();\n assert_eq(zero_bits, [0; 8]);\n\n let zero_bytes: [u8; 8] = 0.to_le_bytes();\n assert_eq(zero_bytes, [0; 8]);\n\n let one_bits: [u1; 8] = 1.to_le_bits();\n let expected: [u1; 8] = [1, 0, 0, 0, 0, 0, 0, 0];\n assert_eq(one_bits, expected);\n\n let pow2_bits: [u1; 8] = 4.to_le_bits();\n let expected: [u1; 8] = [0, 0, 1, 0, 0, 0, 0, 0];\n assert_eq(pow2_bits, expected);\n }\n\n #[test]\n fn test_pow_32() {\n assert_eq(2.pow_32(3), 8);\n assert_eq(3.pow_32(2), 9);\n assert_eq(5.pow_32(0), 1);\n assert_eq(7.pow_32(1), 7);\n\n assert_eq(2.pow_32(10), 1024);\n\n assert_eq(0.pow_32(5), 0);\n assert_eq(0.pow_32(0), 1);\n\n assert_eq(1.pow_32(100), 1);\n }\n\n #[test]\n fn test_sgn0() {\n assert_eq(0.sgn0(), 0);\n assert_eq(2.sgn0(), 0);\n assert_eq(4.sgn0(), 0);\n assert_eq(100.sgn0(), 0);\n\n assert_eq(1.sgn0(), 1);\n assert_eq(3.sgn0(), 1);\n assert_eq(5.sgn0(), 1);\n assert_eq(101.sgn0(), 1);\n }\n\n #[test(should_fail_with = \"Field failed to decompose into specified 8 limbs\")]\n fn test_bit_decomposition_overflow() {\n // 8 bits can't represent large field values\n let large_val = 0x1000000000000000;\n let _: [u1; 8] = large_val.to_le_bits();\n }\n\n #[test(should_fail_with = \"Field failed to decompose into specified 4 limbs\")]\n fn test_byte_decomposition_overflow() {\n // 4 bytes can't represent large field values\n let large_val = 0x1000000000000000;\n let _: [u8; 4] = large_val.to_le_bytes();\n }\n\n #[test]\n fn test_to_from_be_bytes_bn254_edge_cases() {\n if crate::compat::is_bn254() {\n // checking that decrementing this byte produces the expected 32 BE bytes for (modulus - 1)\n let mut p_minus_1_bytes: [u8; 32] = modulus_be_bytes().as_array();\n assert(p_minus_1_bytes[32 - 1] > 0);\n p_minus_1_bytes[32 - 1] -= 1;\n\n let p_minus_1 = Field::from_be_bytes::<32>(p_minus_1_bytes);\n assert_eq(p_minus_1 + 1, 0);\n\n // checking that converting (modulus - 1) from and then to 32 BE bytes produces the same bytes\n let p_minus_1_converted_bytes: [u8; 32] = p_minus_1.to_be_bytes();\n assert_eq(p_minus_1_converted_bytes, p_minus_1_bytes);\n\n // checking that incrementing this byte produces 32 BE bytes for (modulus + 1)\n let mut p_plus_1_bytes: [u8; 32] = modulus_be_bytes().as_array();\n assert(p_plus_1_bytes[32 - 1] < 255);\n p_plus_1_bytes[32 - 1] += 1;\n\n let p_plus_1 = Field::from_be_bytes::<32>(p_plus_1_bytes);\n assert_eq(p_plus_1, 1);\n\n // checking that converting p_plus_1 to 32 BE bytes produces the same\n // byte set to 1 as p_plus_1_bytes and otherwise zeroes\n let mut p_plus_1_converted_bytes: [u8; 32] = p_plus_1.to_be_bytes();\n assert_eq(p_plus_1_converted_bytes[32 - 1], 1);\n p_plus_1_converted_bytes[32 - 1] = 0;\n assert_eq(p_plus_1_converted_bytes, [0; 32]);\n\n // checking that Field::from_be_bytes::<32> on the Field modulus produces 0\n assert_eq(modulus_be_bytes().len(), 32);\n let p = Field::from_be_bytes::<32>(modulus_be_bytes().as_array());\n assert_eq(p, 0);\n\n // checking that converting 0 to 32 BE bytes produces 32 zeroes\n let p_bytes: [u8; 32] = 0.to_be_bytes();\n assert_eq(p_bytes, [0; 32]);\n }\n }\n\n #[test]\n fn test_to_from_le_bytes_bn254_edge_cases() {\n if crate::compat::is_bn254() {\n // checking that decrementing this byte produces the expected 32 LE bytes for (modulus - 1)\n let mut p_minus_1_bytes: [u8; 32] = modulus_le_bytes().as_array();\n assert(p_minus_1_bytes[0] > 0);\n p_minus_1_bytes[0] -= 1;\n\n let p_minus_1 = Field::from_le_bytes::<32>(p_minus_1_bytes);\n assert_eq(p_minus_1 + 1, 0);\n\n // checking that converting (modulus - 1) from and then to 32 BE bytes produces the same bytes\n let p_minus_1_converted_bytes: [u8; 32] = p_minus_1.to_le_bytes();\n assert_eq(p_minus_1_converted_bytes, p_minus_1_bytes);\n\n // checking that incrementing this byte produces 32 LE bytes for (modulus + 1)\n let mut p_plus_1_bytes: [u8; 32] = modulus_le_bytes().as_array();\n assert(p_plus_1_bytes[0] < 255);\n p_plus_1_bytes[0] += 1;\n\n let p_plus_1 = Field::from_le_bytes::<32>(p_plus_1_bytes);\n assert_eq(p_plus_1, 1);\n\n // checking that converting p_plus_1 to 32 LE bytes produces the same\n // byte set to 1 as p_plus_1_bytes and otherwise zeroes\n let mut p_plus_1_converted_bytes: [u8; 32] = p_plus_1.to_le_bytes();\n assert_eq(p_plus_1_converted_bytes[0], 1);\n p_plus_1_converted_bytes[0] = 0;\n assert_eq(p_plus_1_converted_bytes, [0; 32]);\n\n // checking that Field::from_le_bytes::<32> on the Field modulus produces 0\n assert_eq(modulus_le_bytes().len(), 32);\n let p = Field::from_le_bytes::<32>(modulus_le_bytes().as_array());\n assert_eq(p, 0);\n\n // checking that converting 0 to 32 LE bytes produces 32 zeroes\n let p_bytes: [u8; 32] = 0.to_le_bytes();\n assert_eq(p_bytes, [0; 32]);\n }\n }\n\n /// Convert a little endian bit array to a field element.\n /// If the provided bit array overflows the field modulus then the Field will silently wrap around.\n fn from_le_bits<let N: u32>(bits: [u1; N]) -> Field {\n static_assert(\n N <= modulus_le_bits().len(),\n \"N must be less than or equal to modulus_le_bits().len()\",\n );\n let mut v = 1;\n let mut result = 0;\n\n for i in 0..N {\n result += (bits[i] as Field) * v;\n v = v * 2;\n }\n result\n }\n\n /// Convert a big endian bit array to a field element.\n /// If the provided bit array overflows the field modulus then the Field will silently wrap around.\n fn from_be_bits<let N: u32>(bits: [u1; N]) -> Field {\n let mut v = 1;\n let mut result = 0;\n\n for i in 0..N {\n result += (bits[N - 1 - i] as Field) * v;\n v = v * 2;\n }\n result\n }\n\n #[test]\n fn test_to_from_be_bits_bn254_edge_cases() {\n if crate::compat::is_bn254() {\n // checking that decrementing this bit produces the expected 254 BE bits for (modulus - 1)\n let mut p_minus_1_bits: [u1; 254] = modulus_be_bits().as_array();\n assert(p_minus_1_bits[254 - 1] > 0);\n p_minus_1_bits[254 - 1] -= 1;\n\n let p_minus_1 = from_be_bits::<254>(p_minus_1_bits);\n assert_eq(p_minus_1 + 1, 0);\n\n // checking that converting (modulus - 1) from and then to 254 BE bits produces the same bits\n let p_minus_1_converted_bits: [u1; 254] = p_minus_1.to_be_bits();\n assert_eq(p_minus_1_converted_bits, p_minus_1_bits);\n\n // checking that incrementing this bit produces 254 BE bits for (modulus + 4)\n let mut p_plus_4_bits: [u1; 254] = modulus_be_bits().as_array();\n assert(p_plus_4_bits[254 - 3] < 1);\n p_plus_4_bits[254 - 3] += 1;\n\n let p_plus_4 = from_be_bits::<254>(p_plus_4_bits);\n assert_eq(p_plus_4, 4);\n\n // checking that converting p_plus_4 to 254 BE bits produces the same\n // bit set to 1 as p_plus_4_bits and otherwise zeroes\n let mut p_plus_4_converted_bits: [u1; 254] = p_plus_4.to_be_bits();\n assert_eq(p_plus_4_converted_bits[254 - 3], 1);\n p_plus_4_converted_bits[254 - 3] = 0;\n assert_eq(p_plus_4_converted_bits, [0; 254]);\n\n // checking that Field::from_be_bits::<254> on the Field modulus produces 0\n assert_eq(modulus_be_bits().len(), 254);\n let p = from_be_bits::<254>(modulus_be_bits().as_array());\n assert_eq(p, 0);\n\n // checking that converting 0 to 254 BE bytes produces 254 zeroes\n let p_bits: [u1; 254] = 0.to_be_bits();\n assert_eq(p_bits, [0; 254]);\n }\n }\n\n #[test]\n fn test_to_from_le_bits_bn254_edge_cases() {\n if crate::compat::is_bn254() {\n // checking that decrementing this bit produces the expected 254 LE bits for (modulus - 1)\n let mut p_minus_1_bits: [u1; 254] = modulus_le_bits().as_array();\n assert(p_minus_1_bits[0] > 0);\n p_minus_1_bits[0] -= 1;\n\n let p_minus_1 = from_le_bits::<254>(p_minus_1_bits);\n assert_eq(p_minus_1 + 1, 0);\n\n // checking that converting (modulus - 1) from and then to 254 BE bits produces the same bits\n let p_minus_1_converted_bits: [u1; 254] = p_minus_1.to_le_bits();\n assert_eq(p_minus_1_converted_bits, p_minus_1_bits);\n\n // checking that incrementing this bit produces 254 LE bits for (modulus + 4)\n let mut p_plus_4_bits: [u1; 254] = modulus_le_bits().as_array();\n assert(p_plus_4_bits[2] < 1);\n p_plus_4_bits[2] += 1;\n\n let p_plus_4 = from_le_bits::<254>(p_plus_4_bits);\n assert_eq(p_plus_4, 4);\n\n // checking that converting p_plus_4 to 254 LE bits produces the same\n // bit set to 1 as p_plus_4_bits and otherwise zeroes\n let mut p_plus_4_converted_bits: [u1; 254] = p_plus_4.to_le_bits();\n assert_eq(p_plus_4_converted_bits[2], 1);\n p_plus_4_converted_bits[2] = 0;\n assert_eq(p_plus_4_converted_bits, [0; 254]);\n\n // checking that Field::from_le_bits::<254> on the Field modulus produces 0\n assert_eq(modulus_le_bits().len(), 254);\n let p = from_le_bits::<254>(modulus_le_bits().as_array());\n assert_eq(p, 0);\n\n // checking that converting 0 to 254 LE bytes produces 254 zeroes\n let p_bits: [u1; 254] = 0.to_le_bits();\n assert_eq(p_bits, [0; 254]);\n }\n }\n}\n"
3870
+ "source": "pub mod bn254;\nuse crate::{runtime::is_unconstrained, static_assert};\nuse bn254::lt as bn254_lt;\n\nimpl Field {\n /// Asserts that `self` can be represented in `bit_size` bits.\n ///\n /// # Failures\n /// Causes a constraint failure for `Field` values exceeding `2^{bit_size}`.\n // docs:start:assert_max_bit_size\n pub fn assert_max_bit_size<let BIT_SIZE: u32>(self) {\n // docs:end:assert_max_bit_size\n static_assert(\n BIT_SIZE < modulus_num_bits() as u32,\n \"BIT_SIZE must be less than modulus_num_bits\",\n );\n __assert_max_bit_size(self, BIT_SIZE);\n }\n\n /// Decomposes `self` into its little endian bit decomposition as a `[bool; N]` array.\n /// This array will be zero padded should not all bits be necessary to represent `self`.\n ///\n /// # Failures\n /// Causes a constraint failure for `Field` values exceeding `2^N` as the resulting array will not\n /// be able to represent the original `Field`.\n ///\n /// # Safety\n /// The bit decomposition returned is canonical and is guaranteed to not overflow the modulus.\n // docs:start:to_le_bits\n pub fn to_le_bits<let N: u32>(self: Self) -> [bool; N] {\n // docs:end:to_le_bits\n let bits = __to_le_bits(self);\n\n if !is_unconstrained() {\n // Ensure that the byte decomposition does not overflow the modulus\n let p = modulus_le_bits();\n assert(bits.len() <= p.len());\n let mut ok = bits.len() != p.len();\n for i in 0..N {\n if !ok {\n if (bits[N - 1 - i] != p[N - 1 - i]) {\n assert(p[N - 1 - i]);\n ok = true;\n }\n }\n }\n assert(ok);\n }\n bits\n }\n\n /// Decomposes `self` into its big endian bit decomposition as a `[bool; N]` array.\n /// This array will be zero padded should not all bits be necessary to represent `self`.\n ///\n /// # Failures\n /// Causes a constraint failure for `Field` values exceeding `2^N` as the resulting array will not\n /// be able to represent the original `Field`.\n ///\n /// # Safety\n /// The bit decomposition returned is canonical and is guaranteed to not overflow the modulus.\n // docs:start:to_be_bits\n pub fn to_be_bits<let N: u32>(self: Self) -> [bool; N] {\n // docs:end:to_be_bits\n let bits = __to_be_bits(self);\n\n if !is_unconstrained() {\n // Ensure that the decomposition does not overflow the modulus\n let p = modulus_be_bits();\n assert(bits.len() <= p.len());\n let mut ok = bits.len() != p.len();\n for i in 0..N {\n if !ok {\n if (bits[i] != p[i]) {\n assert(p[i]);\n ok = true;\n }\n }\n }\n assert(ok);\n }\n bits\n }\n\n /// Decomposes `self` into its little endian byte decomposition as a `[u8;N]` array\n /// This array will be zero padded should not all bytes be necessary to represent `self`.\n ///\n /// # Failures\n /// The length N of the array must be big enough to contain all the bytes of the 'self',\n /// and no more than the number of bytes required to represent the field modulus\n ///\n /// # Safety\n /// The result is ensured to be the canonical decomposition of the field element\n // docs:start:to_le_bytes\n pub fn to_le_bytes<let N: u32>(self: Self) -> [u8; N] {\n // docs:end:to_le_bytes\n static_assert(\n N <= modulus_le_bytes().len(),\n \"N must be less than or equal to modulus_le_bytes().len()\",\n );\n // Compute the byte decomposition\n let bytes = self.to_le_radix(256);\n\n if !is_unconstrained() {\n // Ensure that the byte decomposition does not overflow the modulus\n let p = modulus_le_bytes();\n assert(bytes.len() <= p.len());\n let mut ok = bytes.len() != p.len();\n for i in 0..N {\n if !ok {\n if (bytes[N - 1 - i] != p[N - 1 - i]) {\n assert(bytes[N - 1 - i] < p[N - 1 - i]);\n ok = true;\n }\n }\n }\n assert(ok);\n }\n bytes\n }\n\n /// Decomposes `self` into its big endian byte decomposition as a `[u8;N]` array of length required to represent the field modulus\n /// This array will be zero padded should not all bytes be necessary to represent `self`.\n ///\n /// # Failures\n /// The length N of the array must be big enough to contain all the bytes of the 'self',\n /// and no more than the number of bytes required to represent the field modulus\n ///\n /// # Safety\n /// The result is ensured to be the canonical decomposition of the field element\n // docs:start:to_be_bytes\n pub fn to_be_bytes<let N: u32>(self: Self) -> [u8; N] {\n // docs:end:to_be_bytes\n static_assert(\n N <= modulus_le_bytes().len(),\n \"N must be less than or equal to modulus_le_bytes().len()\",\n );\n // Compute the byte decomposition\n let bytes = self.to_be_radix(256);\n\n if !is_unconstrained() {\n // Ensure that the byte decomposition does not overflow the modulus\n let p = modulus_be_bytes();\n assert(bytes.len() <= p.len());\n let mut ok = bytes.len() != p.len();\n for i in 0..N {\n if !ok {\n if (bytes[i] != p[i]) {\n assert(bytes[i] < p[i]);\n ok = true;\n }\n }\n }\n assert(ok);\n }\n bytes\n }\n\n fn to_le_radix<let N: u32>(self: Self, radix: u32) -> [u8; N] {\n // Brillig does not need an immediate radix\n if !crate::runtime::is_unconstrained() {\n static_assert(1 < radix, \"radix must be greater than 1\");\n static_assert(radix <= 256, \"radix must be less than or equal to 256\");\n static_assert(radix & (radix - 1) == 0, \"radix must be a power of 2\");\n }\n __to_le_radix(self, radix)\n }\n\n fn to_be_radix<let N: u32>(self: Self, radix: u32) -> [u8; N] {\n // Brillig does not need an immediate radix\n if !crate::runtime::is_unconstrained() {\n static_assert(1 < radix, \"radix must be greater than 1\");\n static_assert(radix <= 256, \"radix must be less than or equal to 256\");\n static_assert(radix & (radix - 1) == 0, \"radix must be a power of 2\");\n }\n __to_be_radix(self, radix)\n }\n\n // Returns self to the power of the given exponent value.\n // Caution: we assume the exponent fits into 32 bits\n // using a bigger bit size impacts negatively the performance and should be done only if the exponent does not fit in 32 bits\n pub fn pow_32(self, exponent: Field) -> Field {\n let mut r: Field = 1;\n let b: [bool; 32] = exponent.to_le_bits();\n\n for i in 1..33 {\n r *= r;\n r = (b[32 - i] as Field) * (r * self) + (1 - b[32 - i] as Field) * r;\n }\n r\n }\n\n // Parity of (prime) Field element, i.e. sgn0(x mod p) = false if x `elem` {0, ..., p-1} is even, otherwise sgn0(x mod p) = true.\n pub fn sgn0(self) -> bool {\n (self as u8) % 2 == 1\n }\n\n pub fn lt(self, another: Field) -> bool {\n if crate::compat::is_bn254() {\n bn254_lt(self, another)\n } else {\n lt_fallback(self, another)\n }\n }\n\n /// Convert a little endian byte array to a field element.\n /// If the provided byte array overflows the field modulus then the Field will silently wrap around.\n pub fn from_le_bytes<let N: u32>(bytes: [u8; N]) -> Field {\n static_assert(\n N <= modulus_le_bytes().len(),\n \"N must be less than or equal to modulus_le_bytes().len()\",\n );\n let mut v = 1;\n let mut result = 0;\n\n for i in 0..N {\n result += (bytes[i] as Field) * v;\n v = v * 256;\n }\n result\n }\n\n /// Convert a big endian byte array to a field element.\n /// If the provided byte array overflows the field modulus then the Field will silently wrap around.\n pub fn from_be_bytes<let N: u32>(bytes: [u8; N]) -> Field {\n let mut v = 1;\n let mut result = 0;\n\n for i in 0..N {\n result += (bytes[N - 1 - i] as Field) * v;\n v = v * 256;\n }\n result\n }\n}\n\n#[builtin(apply_range_constraint)]\nfn __assert_max_bit_size(value: Field, bit_size: u32) {}\n\n// `_radix` must be less than 256\n#[builtin(to_le_radix)]\nfn __to_le_radix<let N: u32>(value: Field, radix: u32) -> [u8; N] {}\n\n// `_radix` must be less than 256\n#[builtin(to_be_radix)]\nfn __to_be_radix<let N: u32>(value: Field, radix: u32) -> [u8; N] {}\n\n/// Decomposes `self` into its little endian bit decomposition as a `[bool; N]` array.\n/// This array will be zero padded should not all bits be necessary to represent `self`.\n///\n/// # Failures\n/// Causes a constraint failure for `Field` values exceeding `2^N` as the resulting array will not\n/// be able to represent the original `Field`.\n///\n/// # Safety\n/// Values of `N` equal to or greater than the number of bits necessary to represent the `Field` modulus\n/// (e.g. 254 for the BN254 field) allow for multiple bit decompositions. This is due to how the `Field` will\n/// wrap around due to overflow when verifying the decomposition.\n#[builtin(to_le_bits)]\nfn __to_le_bits<let N: u32>(value: Field) -> [bool; N] {}\n\n/// Decomposes `self` into its big endian bit decomposition as a `[bool; N]` array.\n/// This array will be zero padded should not all bits be necessary to represent `self`.\n///\n/// # Failures\n/// Causes a constraint failure for `Field` values exceeding `2^N` as the resulting array will not\n/// be able to represent the original `Field`.\n///\n/// # Safety\n/// Values of `N` equal to or greater than the number of bits necessary to represent the `Field` modulus\n/// (e.g. 254 for the BN254 field) allow for multiple bit decompositions. This is due to how the `Field` will\n/// wrap around due to overflow when verifying the decomposition.\n#[builtin(to_be_bits)]\nfn __to_be_bits<let N: u32>(value: Field) -> [bool; N] {}\n\n#[builtin(modulus_num_bits)]\npub comptime fn modulus_num_bits() -> u64 {}\n\n#[builtin(modulus_be_bits)]\npub comptime fn modulus_be_bits() -> [bool] {}\n\n#[builtin(modulus_le_bits)]\npub comptime fn modulus_le_bits() -> [bool] {}\n\n#[builtin(modulus_be_bytes)]\npub comptime fn modulus_be_bytes() -> [u8] {}\n\n#[builtin(modulus_le_bytes)]\npub comptime fn modulus_le_bytes() -> [u8] {}\n\n/// An unconstrained only built in to efficiently compare fields.\n#[builtin(field_less_than)]\nunconstrained fn __field_less_than(x: Field, y: Field) -> bool {}\n\npub(crate) unconstrained fn field_less_than(x: Field, y: Field) -> bool {\n __field_less_than(x, y)\n}\n\n// Convert a 32 byte array to a field element by modding\npub fn bytes32_to_field(bytes32: [u8; 32]) -> Field {\n // Convert it to a field element\n let mut v = 1;\n let mut high = 0 as Field;\n let mut low = 0 as Field;\n\n for i in 0..16 {\n high = high + (bytes32[15 - i] as Field) * v;\n low = low + (bytes32[16 + 15 - i] as Field) * v;\n v = v * 256;\n }\n // Abuse that a % p + b % p = (a + b) % p and that low < p\n low + high * v\n}\n\nfn lt_fallback(x: Field, y: Field) -> bool {\n if is_unconstrained() {\n // Safety: unconstrained context\n unsafe {\n field_less_than(x, y)\n }\n } else {\n let x_bytes: [u8; 32] = x.to_le_bytes();\n let y_bytes: [u8; 32] = y.to_le_bytes();\n let mut x_is_lt = false;\n let mut done = false;\n for i in 0..32 {\n if (!done) {\n let x_byte = x_bytes[32 - 1 - i] as u8;\n let y_byte = y_bytes[32 - 1 - i] as u8;\n let bytes_match = x_byte == y_byte;\n if !bytes_match {\n x_is_lt = x_byte < y_byte;\n done = true;\n }\n }\n }\n x_is_lt\n }\n}\n\nmod tests {\n use crate::{panic::panic, runtime, static_assert};\n use super::{\n field_less_than, modulus_be_bits, modulus_be_bytes, modulus_le_bits, modulus_le_bytes,\n };\n\n #[test]\n // docs:start:to_be_bits_example\n fn test_to_be_bits() {\n let field = 2;\n let bits: [bool; 8] = field.to_be_bits();\n assert_eq(bits, [false, false, false, false, false, false, true, false]);\n }\n // docs:end:to_be_bits_example\n\n #[test]\n // docs:start:to_le_bits_example\n fn test_to_le_bits() {\n let field = 2;\n let bits: [bool; 8] = field.to_le_bits();\n assert_eq(bits, [false, true, false, false, false, false, false, false]);\n }\n // docs:end:to_le_bits_example\n\n #[test]\n // docs:start:to_be_bytes_example\n fn test_to_be_bytes() {\n let field = 2;\n let bytes: [u8; 8] = field.to_be_bytes();\n assert_eq(bytes, [0, 0, 0, 0, 0, 0, 0, 2]);\n assert_eq(Field::from_be_bytes::<8>(bytes), field);\n }\n // docs:end:to_be_bytes_example\n\n #[test]\n // docs:start:to_le_bytes_example\n fn test_to_le_bytes() {\n let field = 2;\n let bytes: [u8; 8] = field.to_le_bytes();\n assert_eq(bytes, [2, 0, 0, 0, 0, 0, 0, 0]);\n assert_eq(Field::from_le_bytes::<8>(bytes), field);\n }\n // docs:end:to_le_bytes_example\n\n #[test]\n // docs:start:to_be_radix_example\n fn test_to_be_radix() {\n // 259, in base 256, big endian, is [1, 3].\n // i.e. 3 * 256^0 + 1 * 256^1\n let field = 259;\n\n // The radix (in this example, 256) must be a power of 2.\n // The length of the returned byte array can be specified to be\n // >= the amount of space needed.\n let bytes: [u8; 8] = field.to_be_radix(256);\n assert_eq(bytes, [0, 0, 0, 0, 0, 0, 1, 3]);\n assert_eq(Field::from_be_bytes::<8>(bytes), field);\n }\n // docs:end:to_be_radix_example\n\n #[test]\n // docs:start:to_le_radix_example\n fn test_to_le_radix() {\n // 259, in base 256, little endian, is [3, 1].\n // i.e. 3 * 256^0 + 1 * 256^1\n let field = 259;\n\n // The radix (in this example, 256) must be a power of 2.\n // The length of the returned byte array can be specified to be\n // >= the amount of space needed.\n let bytes: [u8; 8] = field.to_le_radix(256);\n assert_eq(bytes, [3, 1, 0, 0, 0, 0, 0, 0]);\n assert_eq(Field::from_le_bytes::<8>(bytes), field);\n }\n // docs:end:to_le_radix_example\n\n #[test(should_fail_with = \"radix must be greater than 1\")]\n fn test_to_le_radix_1() {\n // this test should only fail in constrained mode\n if !runtime::is_unconstrained() {\n let field = 2;\n let _: [u8; 8] = field.to_le_radix(1);\n } else {\n panic(\"radix must be greater than 1\");\n }\n }\n\n // Updated test to account for Brillig restriction that radix must be greater than 2\n #[test(should_fail_with = \"radix must be greater than 1\")]\n fn test_to_le_radix_brillig_1() {\n // this test should only fail in constrained mode\n if !runtime::is_unconstrained() {\n let field = 1;\n let _: [u8; 8] = field.to_le_radix(1);\n } else {\n panic(\"radix must be greater than 1\");\n }\n }\n\n #[test(should_fail_with = \"radix must be a power of 2\")]\n fn test_to_le_radix_3() {\n // this test should only fail in constrained mode\n if !runtime::is_unconstrained() {\n let field = 2;\n let _: [u8; 8] = field.to_le_radix(3);\n } else {\n panic(\"radix must be a power of 2\");\n }\n }\n\n #[test]\n fn test_to_le_radix_brillig_3() {\n // this test should only fail in constrained mode\n if runtime::is_unconstrained() {\n let field = 1;\n let out: [u8; 8] = field.to_le_radix(3);\n let mut expected = [0; 8];\n expected[0] = 1;\n assert(out == expected, \"unexpected result\");\n }\n }\n\n #[test(should_fail_with = \"radix must be less than or equal to 256\")]\n fn test_to_le_radix_512() {\n // this test should only fail in constrained mode\n if !runtime::is_unconstrained() {\n let field = 2;\n let _: [u8; 8] = field.to_le_radix(512);\n } else {\n panic(\"radix must be less than or equal to 256\")\n }\n }\n\n #[test(should_fail_with = \"Field failed to decompose into specified 16 limbs\")]\n unconstrained fn not_enough_limbs_brillig() {\n let _: [u8; 16] = 0x100000000000000000000000000000000.to_le_bytes();\n }\n\n #[test(should_fail_with = \"Field failed to decompose into specified 16 limbs\")]\n fn not_enough_limbs() {\n let _: [u8; 16] = 0x100000000000000000000000000000000.to_le_bytes();\n }\n\n #[test]\n unconstrained fn test_field_less_than() {\n assert(field_less_than(0, 1));\n assert(field_less_than(0, 0x100));\n assert(field_less_than(0x100, 0 - 1));\n assert(!field_less_than(0 - 1, 0));\n }\n\n #[test]\n unconstrained fn test_large_field_values_unconstrained() {\n let large_field = 0xffffffffffffffff;\n\n let bits: [bool; 64] = large_field.to_le_bits();\n assert_eq(bits[0], true);\n\n let bytes: [u8; 8] = large_field.to_le_bytes();\n assert_eq(Field::from_le_bytes::<8>(bytes), large_field);\n\n let radix_bytes: [u8; 8] = large_field.to_le_radix(256);\n assert_eq(Field::from_le_bytes::<8>(radix_bytes), large_field);\n }\n\n #[test]\n fn test_large_field_values() {\n let large_val = 0xffffffffffffffff;\n\n let bits: [bool; 64] = large_val.to_le_bits();\n assert_eq(bits[0], true);\n\n let bytes: [u8; 8] = large_val.to_le_bytes();\n assert_eq(Field::from_le_bytes::<8>(bytes), large_val);\n\n let radix_bytes: [u8; 8] = large_val.to_le_radix(256);\n assert_eq(Field::from_le_bytes::<8>(radix_bytes), large_val);\n }\n\n #[test]\n fn test_decomposition_edge_cases() {\n let zero_bits: [bool; 8] = 0.to_le_bits();\n assert_eq(zero_bits, [false; 8]);\n\n let zero_bytes: [u8; 8] = 0.to_le_bytes();\n assert_eq(zero_bytes, [0; 8]);\n\n let one_bits: [bool; 8] = 1.to_le_bits();\n let expected: [bool; 8] = [true, false, false, false, false, false, false, false];\n assert_eq(one_bits, expected);\n\n let pow2_bits: [bool; 8] = 4.to_le_bits();\n let expected: [bool; 8] = [false, false, true, false, false, false, false, false];\n assert_eq(pow2_bits, expected);\n }\n\n #[test]\n fn test_pow_32() {\n assert_eq(2.pow_32(3), 8);\n assert_eq(3.pow_32(2), 9);\n assert_eq(5.pow_32(0), 1);\n assert_eq(7.pow_32(1), 7);\n\n assert_eq(2.pow_32(10), 1024);\n\n assert_eq(0.pow_32(5), 0);\n assert_eq(0.pow_32(0), 1);\n\n assert_eq(1.pow_32(100), 1);\n }\n\n #[test]\n fn test_sgn0() {\n assert_eq(0.sgn0(), false);\n assert_eq(2.sgn0(), false);\n assert_eq(4.sgn0(), false);\n assert_eq(100.sgn0(), false);\n\n assert_eq(1.sgn0(), true);\n assert_eq(3.sgn0(), true);\n assert_eq(5.sgn0(), true);\n assert_eq(101.sgn0(), true);\n }\n\n #[test(should_fail_with = \"Field failed to decompose into specified 8 limbs\")]\n fn test_bit_decomposition_overflow() {\n // 8 bits can't represent large field values\n let large_val = 0x1000000000000000;\n let _: [bool; 8] = large_val.to_le_bits();\n }\n\n #[test(should_fail_with = \"Field failed to decompose into specified 4 limbs\")]\n fn test_byte_decomposition_overflow() {\n // 4 bytes can't represent large field values\n let large_val = 0x1000000000000000;\n let _: [u8; 4] = large_val.to_le_bytes();\n }\n\n #[test]\n fn test_to_from_be_bytes_bn254_edge_cases() {\n if crate::compat::is_bn254() {\n // checking that decrementing this byte produces the expected 32 BE bytes for (modulus - 1)\n let mut p_minus_1_bytes: [u8; 32] = modulus_be_bytes().as_array();\n assert(p_minus_1_bytes[32 - 1] > 0);\n p_minus_1_bytes[32 - 1] -= 1;\n\n let p_minus_1 = Field::from_be_bytes::<32>(p_minus_1_bytes);\n assert_eq(p_minus_1 + 1, 0);\n\n // checking that converting (modulus - 1) from and then to 32 BE bytes produces the same bytes\n let p_minus_1_converted_bytes: [u8; 32] = p_minus_1.to_be_bytes();\n assert_eq(p_minus_1_converted_bytes, p_minus_1_bytes);\n\n // checking that incrementing this byte produces 32 BE bytes for (modulus + 1)\n let mut p_plus_1_bytes: [u8; 32] = modulus_be_bytes().as_array();\n assert(p_plus_1_bytes[32 - 1] < 255);\n p_plus_1_bytes[32 - 1] += 1;\n\n let p_plus_1 = Field::from_be_bytes::<32>(p_plus_1_bytes);\n assert_eq(p_plus_1, 1);\n\n // checking that converting p_plus_1 to 32 BE bytes produces the same\n // byte set to 1 as p_plus_1_bytes and otherwise zeroes\n let mut p_plus_1_converted_bytes: [u8; 32] = p_plus_1.to_be_bytes();\n assert_eq(p_plus_1_converted_bytes[32 - 1], 1);\n p_plus_1_converted_bytes[32 - 1] = 0;\n assert_eq(p_plus_1_converted_bytes, [0; 32]);\n\n // checking that Field::from_be_bytes::<32> on the Field modulus produces 0\n assert_eq(modulus_be_bytes().len(), 32);\n let p = Field::from_be_bytes::<32>(modulus_be_bytes().as_array());\n assert_eq(p, 0);\n\n // checking that converting 0 to 32 BE bytes produces 32 zeroes\n let p_bytes: [u8; 32] = 0.to_be_bytes();\n assert_eq(p_bytes, [0; 32]);\n }\n }\n\n #[test]\n fn test_to_from_le_bytes_bn254_edge_cases() {\n if crate::compat::is_bn254() {\n // checking that decrementing this byte produces the expected 32 LE bytes for (modulus - 1)\n let mut p_minus_1_bytes: [u8; 32] = modulus_le_bytes().as_array();\n assert(p_minus_1_bytes[0] > 0);\n p_minus_1_bytes[0] -= 1;\n\n let p_minus_1 = Field::from_le_bytes::<32>(p_minus_1_bytes);\n assert_eq(p_minus_1 + 1, 0);\n\n // checking that converting (modulus - 1) from and then to 32 BE bytes produces the same bytes\n let p_minus_1_converted_bytes: [u8; 32] = p_minus_1.to_le_bytes();\n assert_eq(p_minus_1_converted_bytes, p_minus_1_bytes);\n\n // checking that incrementing this byte produces 32 LE bytes for (modulus + 1)\n let mut p_plus_1_bytes: [u8; 32] = modulus_le_bytes().as_array();\n assert(p_plus_1_bytes[0] < 255);\n p_plus_1_bytes[0] += 1;\n\n let p_plus_1 = Field::from_le_bytes::<32>(p_plus_1_bytes);\n assert_eq(p_plus_1, 1);\n\n // checking that converting p_plus_1 to 32 LE bytes produces the same\n // byte set to 1 as p_plus_1_bytes and otherwise zeroes\n let mut p_plus_1_converted_bytes: [u8; 32] = p_plus_1.to_le_bytes();\n assert_eq(p_plus_1_converted_bytes[0], 1);\n p_plus_1_converted_bytes[0] = 0;\n assert_eq(p_plus_1_converted_bytes, [0; 32]);\n\n // checking that Field::from_le_bytes::<32> on the Field modulus produces 0\n assert_eq(modulus_le_bytes().len(), 32);\n let p = Field::from_le_bytes::<32>(modulus_le_bytes().as_array());\n assert_eq(p, 0);\n\n // checking that converting 0 to 32 LE bytes produces 32 zeroes\n let p_bytes: [u8; 32] = 0.to_le_bytes();\n assert_eq(p_bytes, [0; 32]);\n }\n }\n\n /// Convert a little endian bit array to a field element.\n /// If the provided bit array overflows the field modulus then the Field will silently wrap around.\n fn from_le_bits<let N: u32>(bits: [bool; N]) -> Field {\n static_assert(\n N <= modulus_le_bits().len(),\n \"N must be less than or equal to modulus_le_bits().len()\",\n );\n let mut v = 1;\n let mut result = 0;\n\n for i in 0..N {\n result += (bits[i] as Field) * v;\n v = v * 2;\n }\n result\n }\n\n /// Convert a big endian bit array to a field element.\n /// If the provided bit array overflows the field modulus then the Field will silently wrap around.\n fn from_be_bits<let N: u32>(bits: [bool; N]) -> Field {\n let mut v = 1;\n let mut result = 0;\n\n for i in 0..N {\n result += (bits[N - 1 - i] as Field) * v;\n v = v * 2;\n }\n result\n }\n\n #[test]\n fn test_to_from_be_bits_bn254_edge_cases() {\n if crate::compat::is_bn254() {\n // checking that decrementing this bit produces the expected 254 BE bits for (modulus - 1)\n let mut p_minus_1_bits: [bool; 254] = modulus_be_bits().as_array();\n assert(p_minus_1_bits[254 - 1]);\n p_minus_1_bits[254 - 1] = false;\n\n let p_minus_1 = from_be_bits::<254>(p_minus_1_bits);\n assert_eq(p_minus_1 + 1, 0);\n\n // checking that converting (modulus - 1) from and then to 254 BE bits produces the same bits\n let p_minus_1_converted_bits: [bool; 254] = p_minus_1.to_be_bits();\n assert_eq(p_minus_1_converted_bits, p_minus_1_bits);\n\n // checking that incrementing this bit produces 254 BE bits for (modulus + 4)\n let mut p_plus_4_bits: [bool; 254] = modulus_be_bits().as_array();\n assert(!p_plus_4_bits[254 - 3]);\n p_plus_4_bits[254 - 3] = true;\n\n let p_plus_4 = from_be_bits::<254>(p_plus_4_bits);\n assert_eq(p_plus_4, 4);\n\n // checking that converting p_plus_4 to 254 BE bits produces the same\n // bit set to 1 as p_plus_4_bits and otherwise zeroes\n let mut p_plus_4_converted_bits: [bool; 254] = p_plus_4.to_be_bits();\n assert(p_plus_4_converted_bits[254 - 3]);\n p_plus_4_converted_bits[254 - 3] = false;\n assert_eq(p_plus_4_converted_bits, [false; 254]);\n\n // checking that Field::from_be_bits::<254> on the Field modulus produces 0\n assert_eq(modulus_be_bits().len(), 254);\n let p = from_be_bits::<254>(modulus_be_bits().as_array());\n assert_eq(p, 0);\n\n // checking that converting 0 to 254 BE bits produces 254 false values\n let p_bits: [bool; 254] = 0.to_be_bits();\n assert_eq(p_bits, [false; 254]);\n }\n }\n\n #[test]\n fn test_to_from_le_bits_bn254_edge_cases() {\n if crate::compat::is_bn254() {\n // checking that decrementing this bit produces the expected 254 LE bits for (modulus - 1)\n let mut p_minus_1_bits: [bool; 254] = modulus_le_bits().as_array();\n assert(p_minus_1_bits[0]);\n p_minus_1_bits[0] = false;\n\n let p_minus_1 = from_le_bits::<254>(p_minus_1_bits);\n assert_eq(p_minus_1 + 1, 0);\n\n // checking that converting (modulus - 1) from and then to 254 BE bits produces the same bits\n let p_minus_1_converted_bits: [bool; 254] = p_minus_1.to_le_bits();\n assert_eq(p_minus_1_converted_bits, p_minus_1_bits);\n\n // checking that incrementing this bit produces 254 LE bits for (modulus + 4)\n let mut p_plus_4_bits: [bool; 254] = modulus_le_bits().as_array();\n assert(!p_plus_4_bits[2]);\n p_plus_4_bits[2] = true;\n\n let p_plus_4 = from_le_bits::<254>(p_plus_4_bits);\n assert_eq(p_plus_4, 4);\n\n // checking that converting p_plus_4 to 254 LE bits produces the same\n // bit set to 1 as p_plus_4_bits and otherwise zeroes\n let mut p_plus_4_converted_bits: [bool; 254] = p_plus_4.to_le_bits();\n assert(p_plus_4_converted_bits[2]);\n p_plus_4_converted_bits[2] = false;\n assert_eq(p_plus_4_converted_bits, [false; 254]);\n\n // checking that Field::from_le_bits::<254> on the Field modulus produces 0\n assert_eq(modulus_le_bits().len(), 254);\n let p = from_le_bits::<254>(modulus_le_bits().as_array());\n assert_eq(p, 0);\n\n // checking that converting 0 to 254 LE bits produces 254 false values\n let p_bits: [bool; 254] = 0.to_le_bits();\n assert_eq(p_bits, [false; 254]);\n }\n }\n}\n"
3871
3871
  },
3872
3872
  "171": {
3873
3873
  "function_locations": [
@@ -3939,195 +3939,195 @@
3939
3939
  },
3940
3940
  {
3941
3941
  "name": "is_static_call",
3942
- "start": 1078
3942
+ "start": 1080
3943
3943
  },
3944
3944
  {
3945
3945
  "name": "note_hash_exists",
3946
- "start": 1189
3946
+ "start": 1193
3947
3947
  },
3948
3948
  {
3949
3949
  "name": "emit_note_hash",
3950
- "start": 1298
3950
+ "start": 1302
3951
3951
  },
3952
3952
  {
3953
3953
  "name": "nullifier_exists",
3954
- "start": 1408
3954
+ "start": 1414
3955
3955
  },
3956
3956
  {
3957
3957
  "name": "emit_nullifier",
3958
- "start": 1512
3958
+ "start": 1518
3959
3959
  },
3960
3960
  {
3961
3961
  "name": "emit_public_log",
3962
- "start": 1608
3962
+ "start": 1614
3963
3963
  },
3964
3964
  {
3965
3965
  "name": "l1_to_l2_msg_exists",
3966
- "start": 1733
3966
+ "start": 1741
3967
3967
  },
3968
3968
  {
3969
3969
  "name": "send_l2_to_l1_msg",
3970
- "start": 1872
3970
+ "start": 1880
3971
3971
  },
3972
3972
  {
3973
3973
  "name": "call",
3974
- "start": 2072
3974
+ "start": 2080
3975
3975
  },
3976
3976
  {
3977
3977
  "name": "call_static",
3978
- "start": 2302
3978
+ "start": 2310
3979
3979
  },
3980
3980
  {
3981
3981
  "name": "calldata_copy",
3982
- "start": 2478
3982
+ "start": 2486
3983
3983
  },
3984
3984
  {
3985
3985
  "name": "success_copy",
3986
- "start": 2661
3986
+ "start": 2669
3987
3987
  },
3988
3988
  {
3989
3989
  "name": "returndata_size",
3990
- "start": 2738
3990
+ "start": 2746
3991
3991
  },
3992
3992
  {
3993
3993
  "name": "returndata_copy",
3994
- "start": 2851
3994
+ "start": 2859
3995
3995
  },
3996
3996
  {
3997
3997
  "name": "avm_return",
3998
- "start": 3036
3998
+ "start": 3044
3999
3999
  },
4000
4000
  {
4001
4001
  "name": "revert",
4002
- "start": 3413
4002
+ "start": 3421
4003
4003
  },
4004
4004
  {
4005
4005
  "name": "storage_read",
4006
- "start": 3537
4006
+ "start": 3545
4007
4007
  },
4008
4008
  {
4009
4009
  "name": "storage_write",
4010
- "start": 3668
4010
+ "start": 3676
4011
4011
  },
4012
4012
  {
4013
4013
  "name": "address_opcode",
4014
- "start": 3799
4014
+ "start": 3807
4015
4015
  },
4016
4016
  {
4017
4017
  "name": "sender_opcode",
4018
- "start": 3880
4018
+ "start": 3888
4019
4019
  },
4020
4020
  {
4021
4021
  "name": "transaction_fee_opcode",
4022
- "start": 3971
4022
+ "start": 3979
4023
4023
  },
4024
4024
  {
4025
4025
  "name": "chain_id_opcode",
4026
- "start": 4048
4026
+ "start": 4056
4027
4027
  },
4028
4028
  {
4029
4029
  "name": "version_opcode",
4030
- "start": 4124
4030
+ "start": 4132
4031
4031
  },
4032
4032
  {
4033
4033
  "name": "block_number_opcode",
4034
- "start": 4207
4034
+ "start": 4215
4035
4035
  },
4036
4036
  {
4037
4037
  "name": "timestamp_opcode",
4038
- "start": 4285
4038
+ "start": 4293
4039
4039
  },
4040
4040
  {
4041
4041
  "name": "min_fee_per_l2_gas_opcode",
4042
- "start": 4378
4042
+ "start": 4386
4043
4043
  },
4044
4044
  {
4045
4045
  "name": "min_fee_per_da_gas_opcode",
4046
- "start": 4471
4046
+ "start": 4479
4047
4047
  },
4048
4048
  {
4049
4049
  "name": "l2_gas_left_opcode",
4050
- "start": 4551
4050
+ "start": 4559
4051
4051
  },
4052
4052
  {
4053
4053
  "name": "da_gas_left_opcode",
4054
- "start": 4631
4054
+ "start": 4639
4055
4055
  },
4056
4056
  {
4057
4057
  "name": "is_static_call_opcode",
4058
- "start": 4716
4058
+ "start": 4726
4059
4059
  },
4060
4060
  {
4061
4061
  "name": "note_hash_exists_opcode",
4062
- "start": 4838
4062
+ "start": 4850
4063
4063
  },
4064
4064
  {
4065
4065
  "name": "emit_note_hash_opcode",
4066
- "start": 4933
4066
+ "start": 4945
4067
4067
  },
4068
4068
  {
4069
4069
  "name": "nullifier_exists_opcode",
4070
- "start": 5046
4070
+ "start": 5060
4071
4071
  },
4072
4072
  {
4073
4073
  "name": "emit_nullifier_opcode",
4074
- "start": 5142
4074
+ "start": 5156
4075
4075
  },
4076
4076
  {
4077
4077
  "name": "emit_public_log_opcode",
4078
- "start": 5239
4078
+ "start": 5253
4079
4079
  },
4080
4080
  {
4081
4081
  "name": "l1_to_l2_msg_exists_opcode",
4082
- "start": 5368
4082
+ "start": 5384
4083
4083
  },
4084
4084
  {
4085
4085
  "name": "send_l2_to_l1_msg_opcode",
4086
- "start": 5488
4086
+ "start": 5504
4087
4087
  },
4088
4088
  {
4089
4089
  "name": "calldata_copy_opcode",
4090
- "start": 5621
4090
+ "start": 5637
4091
4091
  },
4092
4092
  {
4093
4093
  "name": "returndata_size_opcode",
4094
- "start": 5710
4094
+ "start": 5726
4095
4095
  },
4096
4096
  {
4097
4097
  "name": "returndata_copy_opcode",
4098
- "start": 5832
4098
+ "start": 5848
4099
4099
  },
4100
4100
  {
4101
4101
  "name": "return_opcode",
4102
- "start": 5916
4102
+ "start": 5932
4103
4103
  },
4104
4104
  {
4105
4105
  "name": "revert_opcode",
4106
- "start": 6000
4106
+ "start": 6016
4107
4107
  },
4108
4108
  {
4109
4109
  "name": "call_opcode",
4110
- "start": 6447
4110
+ "start": 6463
4111
4111
  },
4112
4112
  {
4113
4113
  "name": "call_static_opcode",
4114
- "start": 6907
4114
+ "start": 6923
4115
4115
  },
4116
4116
  {
4117
4117
  "name": "success_copy_opcode",
4118
- "start": 6991
4118
+ "start": 7007
4119
4119
  },
4120
4120
  {
4121
4121
  "name": "storage_read_opcode",
4122
- "start": 7120
4122
+ "start": 7136
4123
4123
  },
4124
4124
  {
4125
4125
  "name": "storage_write_opcode",
4126
- "start": 7231
4126
+ "start": 7247
4127
4127
  }
4128
4128
  ],
4129
4129
  "path": "/home/aztec-dev/aztec-packages/noir-projects/aztec-nr/aztec/src/oracle/avm.nr",
4130
- "source": "//! AVM oracles.\n//!\n//! There are only available during public execution. Calling any of them from a private or utility function will\n//! result in runtime errors.\n\nuse crate::protocol::address::{AztecAddress, EthAddress};\n\npub unconstrained fn address() -> AztecAddress {\n address_opcode()\n}\npub unconstrained fn sender() -> AztecAddress {\n sender_opcode()\n}\npub unconstrained fn transaction_fee() -> Field {\n transaction_fee_opcode()\n}\npub unconstrained fn chain_id() -> Field {\n chain_id_opcode()\n}\npub unconstrained fn version() -> Field {\n version_opcode()\n}\npub unconstrained fn block_number() -> u32 {\n block_number_opcode()\n}\npub unconstrained fn timestamp() -> u64 {\n timestamp_opcode()\n}\npub unconstrained fn min_fee_per_l2_gas() -> u128 {\n min_fee_per_l2_gas_opcode()\n}\npub unconstrained fn min_fee_per_da_gas() -> u128 {\n min_fee_per_da_gas_opcode()\n}\npub unconstrained fn l2_gas_left() -> u32 {\n l2_gas_left_opcode()\n}\npub unconstrained fn da_gas_left() -> u32 {\n da_gas_left_opcode()\n}\npub unconstrained fn is_static_call() -> u1 {\n is_static_call_opcode()\n}\npub unconstrained fn note_hash_exists(note_hash: Field, leaf_index: u64) -> u1 {\n note_hash_exists_opcode(note_hash, leaf_index)\n}\npub unconstrained fn emit_note_hash(note_hash: Field) {\n emit_note_hash_opcode(note_hash)\n}\npub unconstrained fn nullifier_exists(siloed_nullifier: Field) -> u1 {\n nullifier_exists_opcode(siloed_nullifier)\n}\npub unconstrained fn emit_nullifier(nullifier: Field) {\n emit_nullifier_opcode(nullifier)\n}\npub unconstrained fn emit_public_log(message: [Field]) {\n emit_public_log_opcode(message)\n}\npub unconstrained fn l1_to_l2_msg_exists(msg_hash: Field, msg_leaf_index: u64) -> u1 {\n l1_to_l2_msg_exists_opcode(msg_hash, msg_leaf_index)\n}\npub unconstrained fn send_l2_to_l1_msg(recipient: EthAddress, content: Field) {\n send_l2_to_l1_msg_opcode(recipient, content)\n}\n\npub unconstrained fn call<let N: u32>(\n l2_gas_allocation: u32,\n da_gas_allocation: u32,\n address: AztecAddress,\n args: [Field; N],\n) {\n call_opcode(l2_gas_allocation, da_gas_allocation, address, N, args)\n}\n\npub unconstrained fn call_static<let N: u32>(\n l2_gas_allocation: u32,\n da_gas_allocation: u32,\n address: AztecAddress,\n args: [Field; N],\n) {\n call_static_opcode(l2_gas_allocation, da_gas_allocation, address, N, args)\n}\n\npub unconstrained fn calldata_copy<let N: u32>(cdoffset: u32, copy_size: u32) -> [Field; N] {\n calldata_copy_opcode(cdoffset, copy_size)\n}\n\n/// `success_copy` is placed immediately after the CALL opcode to get the success value\npub unconstrained fn success_copy() -> bool {\n success_copy_opcode()\n}\n\npub unconstrained fn returndata_size() -> u32 {\n returndata_size_opcode()\n}\n\npub unconstrained fn returndata_copy(rdoffset: u32, copy_size: u32) -> [Field] {\n returndata_copy_opcode(rdoffset, copy_size)\n}\n\n/// The additional prefix is to avoid clashing with the `return` Noir keyword.\npub unconstrained fn avm_return(returndata: [Field]) {\n return_opcode(returndata)\n}\n\n/// This opcode reverts using the exact data given. In general it should only be used to do rethrows, where the revert\n/// data is the same as the original revert data. For normal reverts, use Noir's `assert` which, on top of reverting,\n/// will also add an error selector to the revert data.\npub unconstrained fn revert(revertdata: [Field]) {\n revert_opcode(revertdata)\n}\n\npub unconstrained fn storage_read(storage_slot: Field, contract_address: Field) -> Field {\n storage_read_opcode(storage_slot, contract_address)\n}\n\npub unconstrained fn storage_write(storage_slot: Field, value: Field) {\n storage_write_opcode(storage_slot, value);\n}\n\n#[oracle(aztec_avm_address)]\nunconstrained fn address_opcode() -> AztecAddress {}\n\n#[oracle(aztec_avm_sender)]\nunconstrained fn sender_opcode() -> AztecAddress {}\n\n#[oracle(aztec_avm_transactionFee)]\nunconstrained fn transaction_fee_opcode() -> Field {}\n\n#[oracle(aztec_avm_chainId)]\nunconstrained fn chain_id_opcode() -> Field {}\n\n#[oracle(aztec_avm_version)]\nunconstrained fn version_opcode() -> Field {}\n\n#[oracle(aztec_avm_blockNumber)]\nunconstrained fn block_number_opcode() -> u32 {}\n\n#[oracle(aztec_avm_timestamp)]\nunconstrained fn timestamp_opcode() -> u64 {}\n\n#[oracle(aztec_avm_minFeePerL2Gas)]\nunconstrained fn min_fee_per_l2_gas_opcode() -> u128 {}\n\n#[oracle(aztec_avm_minFeePerDaGas)]\nunconstrained fn min_fee_per_da_gas_opcode() -> u128 {}\n\n#[oracle(aztec_avm_l2GasLeft)]\nunconstrained fn l2_gas_left_opcode() -> u32 {}\n\n#[oracle(aztec_avm_daGasLeft)]\nunconstrained fn da_gas_left_opcode() -> u32 {}\n\n#[oracle(aztec_avm_isStaticCall)]\nunconstrained fn is_static_call_opcode() -> u1 {}\n\n#[oracle(aztec_avm_noteHashExists)]\nunconstrained fn note_hash_exists_opcode(note_hash: Field, leaf_index: u64) -> u1 {}\n\n#[oracle(aztec_avm_emitNoteHash)]\nunconstrained fn emit_note_hash_opcode(note_hash: Field) {}\n\n#[oracle(aztec_avm_nullifierExists)]\nunconstrained fn nullifier_exists_opcode(siloed_nullifier: Field) -> u1 {}\n\n#[oracle(aztec_avm_emitNullifier)]\nunconstrained fn emit_nullifier_opcode(nullifier: Field) {}\n\n#[oracle(aztec_avm_emitPublicLog)]\nunconstrained fn emit_public_log_opcode(message: [Field]) {}\n\n#[oracle(aztec_avm_l1ToL2MsgExists)]\nunconstrained fn l1_to_l2_msg_exists_opcode(msg_hash: Field, msg_leaf_index: u64) -> u1 {}\n\n#[oracle(aztec_avm_sendL2ToL1Msg)]\nunconstrained fn send_l2_to_l1_msg_opcode(recipient: EthAddress, content: Field) {}\n\n#[oracle(aztec_avm_calldataCopy)]\nunconstrained fn calldata_copy_opcode<let N: u32>(cdoffset: u32, copy_size: u32) -> [Field; N] {}\n\n#[oracle(aztec_avm_returndataSize)]\nunconstrained fn returndata_size_opcode() -> u32 {}\n\n#[oracle(aztec_avm_returndataCopy)]\nunconstrained fn returndata_copy_opcode(rdoffset: u32, copy_size: u32) -> [Field] {}\n\n#[oracle(aztec_avm_return)]\nunconstrained fn return_opcode(returndata: [Field]) {}\n\n#[oracle(aztec_avm_revert)]\nunconstrained fn revert_opcode(revertdata: [Field]) {}\n\n// While the length parameter might seem unnecessary given that we have N we keep it around because at the AVM bytecode\n// level, we want to support non-comptime-known lengths for such opcodes, even if Noir code will not generally take\n// that route.\n#[oracle(aztec_avm_call)]\nunconstrained fn call_opcode<let N: u32>(\n l2_gas_allocation: u32,\n da_gas_allocation: u32,\n address: AztecAddress,\n length: u32,\n args: [Field; N],\n) {}\n\n// While the length parameter might seem unnecessary given that we have N we keep it around because at the AVM bytecode\n// level, we want to support non-comptime-known lengths for such opcodes, even if Noir code will not generally take\n// that route.\n#[oracle(aztec_avm_staticCall)]\nunconstrained fn call_static_opcode<let N: u32>(\n l2_gas_allocation: u32,\n da_gas_allocation: u32,\n address: AztecAddress,\n length: u32,\n args: [Field; N],\n) {}\n\n#[oracle(aztec_avm_successCopy)]\nunconstrained fn success_copy_opcode() -> bool {}\n\n#[oracle(aztec_avm_storageRead)]\nunconstrained fn storage_read_opcode(storage_slot: Field, contract_address: Field) -> Field {}\n\n#[oracle(aztec_avm_storageWrite)]\nunconstrained fn storage_write_opcode(storage_slot: Field, value: Field) {}\n"
4130
+ "source": "//! AVM oracles.\n//!\n//! There are only available during public execution. Calling any of them from a private or utility function will\n//! result in runtime errors.\n\nuse crate::protocol::address::{AztecAddress, EthAddress};\n\npub unconstrained fn address() -> AztecAddress {\n address_opcode()\n}\npub unconstrained fn sender() -> AztecAddress {\n sender_opcode()\n}\npub unconstrained fn transaction_fee() -> Field {\n transaction_fee_opcode()\n}\npub unconstrained fn chain_id() -> Field {\n chain_id_opcode()\n}\npub unconstrained fn version() -> Field {\n version_opcode()\n}\npub unconstrained fn block_number() -> u32 {\n block_number_opcode()\n}\npub unconstrained fn timestamp() -> u64 {\n timestamp_opcode()\n}\npub unconstrained fn min_fee_per_l2_gas() -> u128 {\n min_fee_per_l2_gas_opcode()\n}\npub unconstrained fn min_fee_per_da_gas() -> u128 {\n min_fee_per_da_gas_opcode()\n}\npub unconstrained fn l2_gas_left() -> u32 {\n l2_gas_left_opcode()\n}\npub unconstrained fn da_gas_left() -> u32 {\n da_gas_left_opcode()\n}\npub unconstrained fn is_static_call() -> bool {\n is_static_call_opcode()\n}\npub unconstrained fn note_hash_exists(note_hash: Field, leaf_index: u64) -> bool {\n note_hash_exists_opcode(note_hash, leaf_index)\n}\npub unconstrained fn emit_note_hash(note_hash: Field) {\n emit_note_hash_opcode(note_hash)\n}\npub unconstrained fn nullifier_exists(siloed_nullifier: Field) -> bool {\n nullifier_exists_opcode(siloed_nullifier)\n}\npub unconstrained fn emit_nullifier(nullifier: Field) {\n emit_nullifier_opcode(nullifier)\n}\npub unconstrained fn emit_public_log(message: [Field]) {\n emit_public_log_opcode(message)\n}\npub unconstrained fn l1_to_l2_msg_exists(msg_hash: Field, msg_leaf_index: u64) -> bool {\n l1_to_l2_msg_exists_opcode(msg_hash, msg_leaf_index)\n}\npub unconstrained fn send_l2_to_l1_msg(recipient: EthAddress, content: Field) {\n send_l2_to_l1_msg_opcode(recipient, content)\n}\n\npub unconstrained fn call<let N: u32>(\n l2_gas_allocation: u32,\n da_gas_allocation: u32,\n address: AztecAddress,\n args: [Field; N],\n) {\n call_opcode(l2_gas_allocation, da_gas_allocation, address, N, args)\n}\n\npub unconstrained fn call_static<let N: u32>(\n l2_gas_allocation: u32,\n da_gas_allocation: u32,\n address: AztecAddress,\n args: [Field; N],\n) {\n call_static_opcode(l2_gas_allocation, da_gas_allocation, address, N, args)\n}\n\npub unconstrained fn calldata_copy<let N: u32>(cdoffset: u32, copy_size: u32) -> [Field; N] {\n calldata_copy_opcode(cdoffset, copy_size)\n}\n\n/// `success_copy` is placed immediately after the CALL opcode to get the success value\npub unconstrained fn success_copy() -> bool {\n success_copy_opcode()\n}\n\npub unconstrained fn returndata_size() -> u32 {\n returndata_size_opcode()\n}\n\npub unconstrained fn returndata_copy(rdoffset: u32, copy_size: u32) -> [Field] {\n returndata_copy_opcode(rdoffset, copy_size)\n}\n\n/// The additional prefix is to avoid clashing with the `return` Noir keyword.\npub unconstrained fn avm_return(returndata: [Field]) {\n return_opcode(returndata)\n}\n\n/// This opcode reverts using the exact data given. In general it should only be used to do rethrows, where the revert\n/// data is the same as the original revert data. For normal reverts, use Noir's `assert` which, on top of reverting,\n/// will also add an error selector to the revert data.\npub unconstrained fn revert(revertdata: [Field]) {\n revert_opcode(revertdata)\n}\n\npub unconstrained fn storage_read(storage_slot: Field, contract_address: Field) -> Field {\n storage_read_opcode(storage_slot, contract_address)\n}\n\npub unconstrained fn storage_write(storage_slot: Field, value: Field) {\n storage_write_opcode(storage_slot, value);\n}\n\n#[oracle(aztec_avm_address)]\nunconstrained fn address_opcode() -> AztecAddress {}\n\n#[oracle(aztec_avm_sender)]\nunconstrained fn sender_opcode() -> AztecAddress {}\n\n#[oracle(aztec_avm_transactionFee)]\nunconstrained fn transaction_fee_opcode() -> Field {}\n\n#[oracle(aztec_avm_chainId)]\nunconstrained fn chain_id_opcode() -> Field {}\n\n#[oracle(aztec_avm_version)]\nunconstrained fn version_opcode() -> Field {}\n\n#[oracle(aztec_avm_blockNumber)]\nunconstrained fn block_number_opcode() -> u32 {}\n\n#[oracle(aztec_avm_timestamp)]\nunconstrained fn timestamp_opcode() -> u64 {}\n\n#[oracle(aztec_avm_minFeePerL2Gas)]\nunconstrained fn min_fee_per_l2_gas_opcode() -> u128 {}\n\n#[oracle(aztec_avm_minFeePerDaGas)]\nunconstrained fn min_fee_per_da_gas_opcode() -> u128 {}\n\n#[oracle(aztec_avm_l2GasLeft)]\nunconstrained fn l2_gas_left_opcode() -> u32 {}\n\n#[oracle(aztec_avm_daGasLeft)]\nunconstrained fn da_gas_left_opcode() -> u32 {}\n\n#[oracle(aztec_avm_isStaticCall)]\nunconstrained fn is_static_call_opcode() -> bool {}\n\n#[oracle(aztec_avm_noteHashExists)]\nunconstrained fn note_hash_exists_opcode(note_hash: Field, leaf_index: u64) -> bool {}\n\n#[oracle(aztec_avm_emitNoteHash)]\nunconstrained fn emit_note_hash_opcode(note_hash: Field) {}\n\n#[oracle(aztec_avm_nullifierExists)]\nunconstrained fn nullifier_exists_opcode(siloed_nullifier: Field) -> bool {}\n\n#[oracle(aztec_avm_emitNullifier)]\nunconstrained fn emit_nullifier_opcode(nullifier: Field) {}\n\n#[oracle(aztec_avm_emitPublicLog)]\nunconstrained fn emit_public_log_opcode(message: [Field]) {}\n\n#[oracle(aztec_avm_l1ToL2MsgExists)]\nunconstrained fn l1_to_l2_msg_exists_opcode(msg_hash: Field, msg_leaf_index: u64) -> bool {}\n\n#[oracle(aztec_avm_sendL2ToL1Msg)]\nunconstrained fn send_l2_to_l1_msg_opcode(recipient: EthAddress, content: Field) {}\n\n#[oracle(aztec_avm_calldataCopy)]\nunconstrained fn calldata_copy_opcode<let N: u32>(cdoffset: u32, copy_size: u32) -> [Field; N] {}\n\n#[oracle(aztec_avm_returndataSize)]\nunconstrained fn returndata_size_opcode() -> u32 {}\n\n#[oracle(aztec_avm_returndataCopy)]\nunconstrained fn returndata_copy_opcode(rdoffset: u32, copy_size: u32) -> [Field] {}\n\n#[oracle(aztec_avm_return)]\nunconstrained fn return_opcode(returndata: [Field]) {}\n\n#[oracle(aztec_avm_revert)]\nunconstrained fn revert_opcode(revertdata: [Field]) {}\n\n// While the length parameter might seem unnecessary given that we have N we keep it around because at the AVM bytecode\n// level, we want to support non-comptime-known lengths for such opcodes, even if Noir code will not generally take\n// that route.\n#[oracle(aztec_avm_call)]\nunconstrained fn call_opcode<let N: u32>(\n l2_gas_allocation: u32,\n da_gas_allocation: u32,\n address: AztecAddress,\n length: u32,\n args: [Field; N],\n) {}\n\n// While the length parameter might seem unnecessary given that we have N we keep it around because at the AVM bytecode\n// level, we want to support non-comptime-known lengths for such opcodes, even if Noir code will not generally take\n// that route.\n#[oracle(aztec_avm_staticCall)]\nunconstrained fn call_static_opcode<let N: u32>(\n l2_gas_allocation: u32,\n da_gas_allocation: u32,\n address: AztecAddress,\n length: u32,\n args: [Field; N],\n) {}\n\n#[oracle(aztec_avm_successCopy)]\nunconstrained fn success_copy_opcode() -> bool {}\n\n#[oracle(aztec_avm_storageRead)]\nunconstrained fn storage_read_opcode(storage_slot: Field, contract_address: Field) -> Field {}\n\n#[oracle(aztec_avm_storageWrite)]\nunconstrained fn storage_write_opcode(storage_slot: Field, value: Field) {}\n"
4131
4131
  },
4132
4132
  "175": {
4133
4133
  "function_locations": [
@@ -4309,123 +4309,119 @@
4309
4309
  },
4310
4310
  {
4311
4311
  "name": "derive_generators",
4312
- "start": 3591
4312
+ "start": 3597
4313
4313
  },
4314
4314
  {
4315
4315
  "name": "__derive_generators",
4316
- "start": 3950
4316
+ "start": 3956
4317
4317
  },
4318
4318
  {
4319
4319
  "name": "from_field_unsafe",
4320
- "start": 4265
4320
+ "start": 4271
4321
4321
  },
4322
4322
  {
4323
4323
  "name": "poseidon2_permutation",
4324
- "start": 4922
4324
+ "start": 4912
4325
4325
  },
4326
4326
  {
4327
4327
  "name": "poseidon2_permutation_internal",
4328
- "start": 5318
4328
+ "start": 5268
4329
4329
  },
4330
4330
  {
4331
4331
  "name": "poseidon2_config_state_size",
4332
- "start": 5411
4332
+ "start": 5361
4333
4333
  },
4334
4334
  {
4335
4335
  "name": "derive_hash",
4336
- "start": 5722
4336
+ "start": 5672
4337
4337
  },
4338
4338
  {
4339
4339
  "name": "<impl BuildHasher for BuildHasherDefault<H>>::build_hasher",
4340
- "start": 6947
4340
+ "start": 6897
4341
4341
  },
4342
4342
  {
4343
4343
  "name": "<impl Default for BuildHasherDefault<H>>::default",
4344
- "start": 7079
4344
+ "start": 7029
4345
4345
  },
4346
4346
  {
4347
4347
  "name": "<impl Hash for Field>::hash",
4348
- "start": 7211
4349
- },
4350
- {
4351
- "name": "<impl Hash for u1>::hash",
4352
- "start": 7341
4348
+ "start": 7161
4353
4349
  },
4354
4350
  {
4355
4351
  "name": "<impl Hash for u8>::hash",
4356
- "start": 7480
4352
+ "start": 7291
4357
4353
  },
4358
4354
  {
4359
4355
  "name": "<impl Hash for u16>::hash",
4360
- "start": 7620
4356
+ "start": 7431
4361
4357
  },
4362
4358
  {
4363
4359
  "name": "<impl Hash for u32>::hash",
4364
- "start": 7760
4360
+ "start": 7571
4365
4361
  },
4366
4362
  {
4367
4363
  "name": "<impl Hash for u64>::hash",
4368
- "start": 7900
4364
+ "start": 7711
4369
4365
  },
4370
4366
  {
4371
4367
  "name": "<impl Hash for u128>::hash",
4372
- "start": 8041
4368
+ "start": 7852
4373
4369
  },
4374
4370
  {
4375
4371
  "name": "<impl Hash for i8>::hash",
4376
- "start": 8180
4372
+ "start": 7991
4377
4373
  },
4378
4374
  {
4379
4375
  "name": "<impl Hash for i16>::hash",
4380
- "start": 8326
4376
+ "start": 8137
4381
4377
  },
4382
4378
  {
4383
4379
  "name": "<impl Hash for i32>::hash",
4384
- "start": 8473
4380
+ "start": 8284
4385
4381
  },
4386
4382
  {
4387
4383
  "name": "<impl Hash for i64>::hash",
4388
- "start": 8620
4384
+ "start": 8431
4389
4385
  },
4390
4386
  {
4391
4387
  "name": "<impl Hash for bool>::hash",
4392
- "start": 8768
4388
+ "start": 8579
4393
4389
  },
4394
4390
  {
4395
4391
  "name": "<impl Hash for ()>::hash",
4396
- "start": 8915
4392
+ "start": 8726
4397
4393
  },
4398
4394
  {
4399
4395
  "name": "<impl Hash for [T; N]>::hash",
4400
- "start": 9047
4396
+ "start": 8858
4401
4397
  },
4402
4398
  {
4403
4399
  "name": "<impl Hash for [T]>::hash",
4404
- "start": 9236
4400
+ "start": 9047
4405
4401
  },
4406
4402
  {
4407
4403
  "name": "<impl Hash for (A, B)>::hash",
4408
- "start": 9476
4404
+ "start": 9287
4409
4405
  },
4410
4406
  {
4411
4407
  "name": "<impl Hash for (A, B, C)>::hash",
4412
- "start": 9692
4408
+ "start": 9503
4413
4409
  },
4414
4410
  {
4415
4411
  "name": "<impl Hash for (A, B, C, D)>::hash",
4416
- "start": 9955
4412
+ "start": 9766
4417
4413
  },
4418
4414
  {
4419
4415
  "name": "<impl Hash for (A, B, C, D, E)>::hash",
4420
- "start": 10265
4416
+ "start": 10076
4421
4417
  },
4422
4418
  {
4423
4419
  "name": "assert_pedersen",
4424
- "start": 10661
4420
+ "start": 10472
4425
4421
  }
4426
4422
  ],
4427
4423
  "path": "std/hash/mod.nr",
4428
- "source": "// Exposed only for usage in `std::meta`\npub(crate) mod poseidon2;\n\nuse crate::default::Default;\nuse crate::embedded_curve_ops::{\n EmbeddedCurvePoint, EmbeddedCurveScalar, multi_scalar_mul, multi_scalar_mul_array_return,\n};\nuse crate::meta::derive_via;\nuse crate::static_assert;\n\n/// The size of the state accepted by the backend in `poseidon2_permutation`.\nglobal POSEIDON2_CONFIG_STATE_SIZE: u32 = poseidon2_config_state_size();\n\n#[foreign(sha256_compression)]\n// docs:start:sha256_compression\npub fn sha256_compression(input: [u32; 16], state: [u32; 8]) -> [u32; 8] {}\n// docs:end:sha256_compression\n\n#[foreign(keccakf1600)]\n// docs:start:keccakf1600\npub fn keccakf1600(input: [u64; 25]) -> [u64; 25] {}\n// docs:end:keccakf1600\n\npub mod keccak {\n #[deprecated(\"This function has been moved to std::hash::keccakf1600\")]\n pub fn keccakf1600(input: [u64; 25]) -> [u64; 25] {\n super::keccakf1600(input)\n }\n}\n\n#[foreign(blake2s)]\n// docs:start:blake2s\npub fn blake2s<let N: u32>(input: [u8; N]) -> [u8; 32]\n// docs:end:blake2s\n{}\n\n// docs:start:blake3\npub fn blake3<let N: u32>(input: [u8; N]) -> [u8; 32]\n// docs:end:blake3\n{\n if crate::runtime::is_unconstrained() {\n // Temporary measure while Barretenberg is main proving system.\n // Please open an issue if you're working on another proving system and running into problems due to this.\n crate::static_assert(\n N <= 1024,\n \"Barretenberg cannot prove blake3 hashes with inputs larger than 1024 bytes\",\n );\n }\n __blake3(input)\n}\n\n#[foreign(blake3)]\nfn __blake3<let N: u32>(input: [u8; N]) -> [u8; 32] {}\n\n// docs:start:pedersen_commitment\npub fn pedersen_commitment<let N: u32>(input: [Field; N]) -> EmbeddedCurvePoint {\n // docs:end:pedersen_commitment\n pedersen_commitment_with_separator(input, 0)\n}\n\n#[inline_always]\npub fn pedersen_commitment_with_separator<let N: u32>(\n input: [Field; N],\n separator: u32,\n) -> EmbeddedCurvePoint {\n let mut points = [EmbeddedCurveScalar { lo: 0, hi: 0 }; N];\n for i in 0..N {\n // we use the unsafe version because the multi_scalar_mul will constrain the scalars.\n points[i] = from_field_unsafe(input[i]);\n }\n let generators = derive_generators(\"DEFAULT_DOMAIN_SEPARATOR\".as_bytes(), separator);\n multi_scalar_mul(generators, points)\n}\n\n// docs:start:pedersen_hash\npub fn pedersen_hash<let N: u32>(input: [Field; N]) -> Field\n// docs:end:pedersen_hash\n{\n pedersen_hash_with_separator(input, 0)\n}\n\n#[no_predicates]\npub fn pedersen_hash_with_separator<let N: u32>(input: [Field; N], separator: u32) -> Field {\n let mut scalars: [EmbeddedCurveScalar; N + 1] = [EmbeddedCurveScalar { lo: 0, hi: 0 }; N + 1];\n let mut generators: [EmbeddedCurvePoint; N + 1] =\n [EmbeddedCurvePoint::point_at_infinity(); N + 1];\n crate::assert_constant(separator);\n let domain_generators: [EmbeddedCurvePoint; N] =\n derive_generators(\"DEFAULT_DOMAIN_SEPARATOR\".as_bytes(), separator);\n\n for i in 0..N {\n scalars[i] = from_field_unsafe(input[i]);\n generators[i] = domain_generators[i];\n }\n scalars[N] = EmbeddedCurveScalar { lo: N as Field, hi: 0 as Field };\n\n let length_generator: [EmbeddedCurvePoint; 1] =\n derive_generators(\"pedersen_hash_length\".as_bytes(), 0);\n generators[N] = length_generator[0];\n multi_scalar_mul_array_return(generators, scalars)[0].x\n}\n\n#[field(bn254)]\n#[inline_always]\npub fn derive_generators<let N: u32, let M: u32>(\n domain_separator_bytes: [u8; M],\n starting_index: u32,\n) -> [EmbeddedCurvePoint; N] {\n crate::assert_constant(domain_separator_bytes);\n crate::assert_constant(starting_index);\n __derive_generators(domain_separator_bytes, starting_index)\n}\n\n#[builtin(derive_pedersen_generators)]\n#[field(bn254)]\nfn __derive_generators<let N: u32, let M: u32>(\n domain_separator_bytes: [u8; M],\n starting_index: u32,\n) -> [EmbeddedCurvePoint; N] {}\n\n#[field(bn254)]\n// Decompose the input 'bn254 scalar' into two 128 bits limbs.\n// It is called 'unsafe' because it does not assert the limbs are 128 bits\n// Assuming the limbs are 128 bits:\n// Assert the decomposition does not overflow the field size.\nfn from_field_unsafe(scalar: Field) -> EmbeddedCurveScalar {\n // Safety: xlo and xhi decomposition is checked below\n let (xlo, xhi) = unsafe { crate::field::bn254::decompose_hint(scalar) };\n // Check that the decomposition is correct\n assert_eq(scalar, xlo + crate::field::bn254::TWO_POW_128 * xhi);\n // Check that the decomposition does not overflow the field size\n let (a, b) = if xhi == crate::field::bn254::PHI {\n (xlo, crate::field::bn254::PLO)\n } else {\n (xhi, crate::field::bn254::PHI)\n };\n crate::field::bn254::assert_lt(a, b);\n\n EmbeddedCurveScalar { lo: xlo, hi: xhi }\n}\n\npub fn poseidon2_permutation<let N: u32>(input: [Field; N], state_len: u32) -> [Field; N] {\n assert_eq(input.len(), state_len);\n\n static_assert(\n N == POSEIDON2_CONFIG_STATE_SIZE,\n f\"the input length must equal the state size in the Poseidon2 config; expected {POSEIDON2_CONFIG_STATE_SIZE}, got {N}\",\n );\n poseidon2_permutation_internal(input)\n}\n\n#[foreign(poseidon2_permutation)]\nfn poseidon2_permutation_internal<let N: u32>(input: [Field; N]) -> [Field; N] {}\n\n#[foreign(poseidon2_config_state_size)]\ncomptime fn poseidon2_config_state_size() -> u32 {}\n\n// Generic hashing support.\n// Partially ported and impacted by rust.\n\n// Hash trait shall be implemented per type.\n#[derive_via(derive_hash)]\npub trait Hash {\n fn hash<H>(self, state: &mut H)\n where\n H: Hasher;\n}\n\n// docs:start:derive_hash\ncomptime fn derive_hash(s: TypeDefinition) -> Quoted {\n let name = quote { $crate::hash::Hash };\n let signature = quote { fn hash<H>(_self: Self, _state: &mut H) where H: $crate::hash::Hasher };\n let for_each_field = |name| quote { _self.$name.hash(_state); };\n crate::meta::make_trait_impl(\n s,\n name,\n signature,\n for_each_field,\n quote {},\n |fields| fields,\n )\n}\n// docs:end:derive_hash\n\n// Hasher trait shall be implemented by algorithms to provide hash-agnostic means.\n// TODO: consider making the types generic here ([u8], [Field], etc.)\npub trait Hasher {\n fn finish(self) -> Field;\n\n /// Returns the hash value without consuming the hasher.\n /// Override this for more efficient implementations that avoid copying.\n /// TODO: deprecate finish() and replace it\n fn finish_ref(&self) -> Field {\n (*self).finish()\n }\n\n fn write(&mut self, input: Field);\n}\n\n// BuildHasher is a factory trait, responsible for production of specific Hasher.\npub trait BuildHasher {\n type H: Hasher;\n\n fn build_hasher(self) -> H;\n}\n\npub struct BuildHasherDefault<H>;\n\nimpl<H> BuildHasher for BuildHasherDefault<H>\nwhere\n H: Hasher + Default,\n{\n type H = H;\n\n fn build_hasher(_self: Self) -> H {\n H::default()\n }\n}\n\nimpl<H> Default for BuildHasherDefault<H>\nwhere\n H: Hasher + Default,\n{\n fn default() -> Self {\n BuildHasherDefault {}\n }\n}\n\nimpl Hash for Field {\n fn hash<H>(self, state: &mut H)\n where\n H: Hasher,\n {\n H::write(state, self);\n }\n}\n\nimpl Hash for u1 {\n fn hash<H>(self, state: &mut H)\n where\n H: Hasher,\n {\n H::write(state, self as Field);\n }\n}\n\nimpl Hash for u8 {\n fn hash<H>(self, state: &mut H)\n where\n H: Hasher,\n {\n H::write(state, self as Field);\n }\n}\n\nimpl Hash for u16 {\n fn hash<H>(self, state: &mut H)\n where\n H: Hasher,\n {\n H::write(state, self as Field);\n }\n}\n\nimpl Hash for u32 {\n fn hash<H>(self, state: &mut H)\n where\n H: Hasher,\n {\n H::write(state, self as Field);\n }\n}\n\nimpl Hash for u64 {\n fn hash<H>(self, state: &mut H)\n where\n H: Hasher,\n {\n H::write(state, self as Field);\n }\n}\n\nimpl Hash for u128 {\n fn hash<H>(self, state: &mut H)\n where\n H: Hasher,\n {\n H::write(state, self as Field);\n }\n}\n\nimpl Hash for i8 {\n fn hash<H>(self, state: &mut H)\n where\n H: Hasher,\n {\n H::write(state, self as u8 as Field);\n }\n}\n\nimpl Hash for i16 {\n fn hash<H>(self, state: &mut H)\n where\n H: Hasher,\n {\n H::write(state, self as u16 as Field);\n }\n}\n\nimpl Hash for i32 {\n fn hash<H>(self, state: &mut H)\n where\n H: Hasher,\n {\n H::write(state, self as u32 as Field);\n }\n}\n\nimpl Hash for i64 {\n fn hash<H>(self, state: &mut H)\n where\n H: Hasher,\n {\n H::write(state, self as u64 as Field);\n }\n}\n\nimpl Hash for bool {\n fn hash<H>(self, state: &mut H)\n where\n H: Hasher,\n {\n H::write(state, self as Field);\n }\n}\n\nimpl Hash for () {\n fn hash<H>(_self: Self, _state: &mut H)\n where\n H: Hasher,\n {}\n}\n\nimpl<T, let N: u32> Hash for [T; N]\nwhere\n T: Hash,\n{\n fn hash<H>(self, state: &mut H)\n where\n H: Hasher,\n {\n for elem in self {\n elem.hash(state);\n }\n }\n}\n\nimpl<T> Hash for [T]\nwhere\n T: Hash,\n{\n fn hash<H>(self, state: &mut H)\n where\n H: Hasher,\n {\n self.len().hash(state);\n for elem in self {\n elem.hash(state);\n }\n }\n}\n\nimpl<A, B> Hash for (A, B)\nwhere\n A: Hash,\n B: Hash,\n{\n fn hash<H>(self, state: &mut H)\n where\n H: Hasher,\n {\n self.0.hash(state);\n self.1.hash(state);\n }\n}\n\nimpl<A, B, C> Hash for (A, B, C)\nwhere\n A: Hash,\n B: Hash,\n C: Hash,\n{\n fn hash<H>(self, state: &mut H)\n where\n H: Hasher,\n {\n self.0.hash(state);\n self.1.hash(state);\n self.2.hash(state);\n }\n}\n\nimpl<A, B, C, D> Hash for (A, B, C, D)\nwhere\n A: Hash,\n B: Hash,\n C: Hash,\n D: Hash,\n{\n fn hash<H>(self, state: &mut H)\n where\n H: Hasher,\n {\n self.0.hash(state);\n self.1.hash(state);\n self.2.hash(state);\n self.3.hash(state);\n }\n}\n\nimpl<A, B, C, D, E> Hash for (A, B, C, D, E)\nwhere\n A: Hash,\n B: Hash,\n C: Hash,\n D: Hash,\n E: Hash,\n{\n fn hash<H>(self, state: &mut H)\n where\n H: Hasher,\n {\n self.0.hash(state);\n self.1.hash(state);\n self.2.hash(state);\n self.3.hash(state);\n self.4.hash(state);\n }\n}\n\n// Some test vectors for Pedersen hash and Pedersen Commitment.\n// They have been generated using the same functions so the tests are for now useless\n// but they will be useful when we switch to Noir implementation.\n#[test]\nfn assert_pedersen() {\n assert_eq(\n pedersen_hash_with_separator([1], 1),\n 0x1b3f4b1a83092a13d8d1a59f7acb62aba15e7002f4440f2275edb99ebbc2305f,\n );\n assert_eq(\n pedersen_commitment_with_separator([1], 1),\n EmbeddedCurvePoint {\n x: 0x054aa86a73cb8a34525e5bbed6e43ba1198e860f5f3950268f71df4591bde402,\n y: 0x209dcfbf2cfb57f9f6046f44d71ac6faf87254afc7407c04eb621a6287cac126,\n is_infinite: false,\n },\n );\n\n assert_eq(\n pedersen_hash_with_separator([1, 2], 2),\n 0x26691c129448e9ace0c66d11f0a16d9014a9e8498ee78f4d69f0083168188255,\n );\n assert_eq(\n pedersen_commitment_with_separator([1, 2], 2),\n EmbeddedCurvePoint {\n x: 0x2e2b3b191e49541fe468ec6877721d445dcaffe41728df0a0eafeb15e87b0753,\n y: 0x2ff4482400ad3a6228be17a2af33e2bcdf41be04795f9782bd96efe7e24f8778,\n is_infinite: false,\n },\n );\n assert_eq(\n pedersen_hash_with_separator([1, 2, 3], 3),\n 0x0bc694b7a1f8d10d2d8987d07433f26bd616a2d351bc79a3c540d85b6206dbe4,\n );\n assert_eq(\n pedersen_commitment_with_separator([1, 2, 3], 3),\n EmbeddedCurvePoint {\n x: 0x1fee4e8cf8d2f527caa2684236b07c4b1bad7342c01b0f75e9a877a71827dc85,\n y: 0x2f9fedb9a090697ab69bf04c8bc15f7385b3e4b68c849c1536e5ae15ff138fd1,\n is_infinite: false,\n },\n );\n assert_eq(\n pedersen_hash_with_separator([1, 2, 3, 4], 4),\n 0xdae10fb32a8408521803905981a2b300d6a35e40e798743e9322b223a5eddc,\n );\n assert_eq(\n pedersen_commitment_with_separator([1, 2, 3, 4], 4),\n EmbeddedCurvePoint {\n x: 0x07ae3e202811e1fca39c2d81eabe6f79183978e6f12be0d3b8eda095b79bdbc9,\n y: 0x0afc6f892593db6fbba60f2da558517e279e0ae04f95758587760ba193145014,\n is_infinite: false,\n },\n );\n assert_eq(\n pedersen_hash_with_separator([1, 2, 3, 4, 5], 5),\n 0xfc375b062c4f4f0150f7100dfb8d9b72a6d28582dd9512390b0497cdad9c22,\n );\n assert_eq(\n pedersen_commitment_with_separator([1, 2, 3, 4, 5], 5),\n EmbeddedCurvePoint {\n x: 0x1754b12bd475a6984a1094b5109eeca9838f4f81ac89c5f0a41dbce53189bb29,\n y: 0x2da030e3cfcdc7ddad80eaf2599df6692cae0717d4e9f7bfbee8d073d5d278f7,\n is_infinite: false,\n },\n );\n assert_eq(\n pedersen_hash_with_separator([1, 2, 3, 4, 5, 6], 6),\n 0x1696ed13dc2730062a98ac9d8f9de0661bb98829c7582f699d0273b18c86a572,\n );\n assert_eq(\n pedersen_commitment_with_separator([1, 2, 3, 4, 5, 6], 6),\n EmbeddedCurvePoint {\n x: 0x190f6c0e97ad83e1e28da22a98aae156da083c5a4100e929b77e750d3106a697,\n y: 0x1f4b60f34ef91221a0b49756fa0705da93311a61af73d37a0c458877706616fb,\n is_infinite: false,\n },\n );\n assert_eq(\n pedersen_hash_with_separator([1, 2, 3, 4, 5, 6, 7], 7),\n 0x128c0ff144fc66b6cb60eeac8a38e23da52992fc427b92397a7dffd71c45ede3,\n );\n assert_eq(\n pedersen_commitment_with_separator([1, 2, 3, 4, 5, 6, 7], 7),\n EmbeddedCurvePoint {\n x: 0x015441e9d29491b06563fac16fc76abf7a9534c715421d0de85d20dbe2965939,\n y: 0x1d2575b0276f4e9087e6e07c2cb75aa1baafad127af4be5918ef8a2ef2fea8fc,\n is_infinite: false,\n },\n );\n assert_eq(\n pedersen_hash_with_separator([1, 2, 3, 4, 5, 6, 7, 8], 8),\n 0x2f960e117482044dfc99d12fece2ef6862fba9242be4846c7c9a3e854325a55c,\n );\n assert_eq(\n pedersen_commitment_with_separator([1, 2, 3, 4, 5, 6, 7, 8], 8),\n EmbeddedCurvePoint {\n x: 0x1657737676968887fceb6dd516382ea13b3a2c557f509811cd86d5d1199bc443,\n y: 0x1f39f0cb569040105fa1e2f156521e8b8e08261e635a2b210bdc94e8d6d65f77,\n is_infinite: false,\n },\n );\n assert_eq(\n pedersen_hash_with_separator([1, 2, 3, 4, 5, 6, 7, 8, 9], 9),\n 0x0c96db0790602dcb166cc4699e2d306c479a76926b81c2cb2aaa92d249ec7be7,\n );\n assert_eq(\n pedersen_commitment_with_separator([1, 2, 3, 4, 5, 6, 7, 8, 9], 9),\n EmbeddedCurvePoint {\n x: 0x0a3ceae42d14914a432aa60ec7fded4af7dad7dd4acdbf2908452675ec67e06d,\n y: 0xfc19761eaaf621ad4aec9a8b2e84a4eceffdba78f60f8b9391b0bd9345a2f2,\n is_infinite: false,\n },\n );\n assert_eq(\n pedersen_hash_with_separator([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 10),\n 0x2cd37505871bc460a62ea1e63c7fe51149df5d0801302cf1cbc48beb8dff7e94,\n );\n assert_eq(\n pedersen_commitment_with_separator([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 10),\n EmbeddedCurvePoint {\n x: 0x2fb3f8b3d41ddde007c8c3c62550f9a9380ee546fcc639ffbb3fd30c8d8de30c,\n y: 0x300783be23c446b11a4c0fabf6c91af148937cea15fcf5fb054abf7f752ee245,\n is_infinite: false,\n },\n );\n}\n"
4424
+ "source": "// Exposed only for usage in `std::meta`\npub(crate) mod poseidon2;\n\nuse crate::default::Default;\nuse crate::embedded_curve_ops::{\n EmbeddedCurvePoint, EmbeddedCurveScalar, multi_scalar_mul, multi_scalar_mul_array_return,\n};\nuse crate::meta::derive_via;\nuse crate::static_assert;\n\n/// The size of the state accepted by the backend in `poseidon2_permutation`.\nglobal POSEIDON2_CONFIG_STATE_SIZE: u32 = poseidon2_config_state_size();\n\n#[foreign(sha256_compression)]\n// docs:start:sha256_compression\npub fn sha256_compression(input: [u32; 16], state: [u32; 8]) -> [u32; 8] {}\n// docs:end:sha256_compression\n\n#[foreign(keccakf1600)]\n// docs:start:keccakf1600\npub fn keccakf1600(input: [u64; 25]) -> [u64; 25] {}\n// docs:end:keccakf1600\n\npub mod keccak {\n #[deprecated(\"This function has been moved to std::hash::keccakf1600\")]\n pub fn keccakf1600(input: [u64; 25]) -> [u64; 25] {\n super::keccakf1600(input)\n }\n}\n\n#[foreign(blake2s)]\n// docs:start:blake2s\npub fn blake2s<let N: u32>(input: [u8; N]) -> [u8; 32]\n// docs:end:blake2s\n{}\n\n// docs:start:blake3\npub fn blake3<let N: u32>(input: [u8; N]) -> [u8; 32]\n// docs:end:blake3\n{\n if crate::runtime::is_unconstrained() {\n // Temporary measure while Barretenberg is main proving system.\n // Please open an issue if you're working on another proving system and running into problems due to this.\n crate::static_assert(\n N <= 1024,\n \"Barretenberg cannot prove blake3 hashes with inputs larger than 1024 bytes\",\n );\n }\n __blake3(input)\n}\n\n#[foreign(blake3)]\nfn __blake3<let N: u32>(input: [u8; N]) -> [u8; 32] {}\n\n// docs:start:pedersen_commitment\npub fn pedersen_commitment<let N: u32>(input: [Field; N]) -> EmbeddedCurvePoint {\n // docs:end:pedersen_commitment\n pedersen_commitment_with_separator(input, 0)\n}\n\n#[inline_always]\npub fn pedersen_commitment_with_separator<let N: u32>(\n input: [Field; N],\n separator: u32,\n) -> EmbeddedCurvePoint {\n let mut points = [EmbeddedCurveScalar { lo: 0, hi: 0 }; N];\n for i in 0..N {\n // we use the unsafe version because the multi_scalar_mul will constrain the scalars.\n points[i] = from_field_unsafe(input[i]);\n }\n let generators = derive_generators(\"DEFAULT_DOMAIN_SEPARATOR\".as_bytes(), separator);\n multi_scalar_mul(generators, points)\n}\n\n// docs:start:pedersen_hash\npub fn pedersen_hash<let N: u32>(input: [Field; N]) -> Field\n// docs:end:pedersen_hash\n{\n pedersen_hash_with_separator(input, 0)\n}\n\n#[no_predicates]\npub fn pedersen_hash_with_separator<let N: u32>(input: [Field; N], separator: u32) -> Field {\n let mut scalars: [EmbeddedCurveScalar; N + 1] = [EmbeddedCurveScalar { lo: 0, hi: 0 }; N + 1];\n let mut generators: [EmbeddedCurvePoint; N + 1] =\n [EmbeddedCurvePoint::point_at_infinity(); N + 1];\n crate::assert_constant(separator);\n let domain_generators: [EmbeddedCurvePoint; N] =\n derive_generators(\"DEFAULT_DOMAIN_SEPARATOR\".as_bytes(), separator);\n\n for i in 0..N {\n scalars[i] = from_field_unsafe(input[i]);\n generators[i] = domain_generators[i];\n }\n scalars[N] = EmbeddedCurveScalar { lo: N as Field, hi: 0 as Field };\n\n let length_generator: [EmbeddedCurvePoint; 1] =\n derive_generators(\"pedersen_hash_length\".as_bytes(), 0);\n generators[N] = length_generator[0];\n multi_scalar_mul_array_return(generators, scalars, true)[0].x\n}\n\n#[field(bn254)]\n#[inline_always]\npub fn derive_generators<let N: u32, let M: u32>(\n domain_separator_bytes: [u8; M],\n starting_index: u32,\n) -> [EmbeddedCurvePoint; N] {\n crate::assert_constant(domain_separator_bytes);\n crate::assert_constant(starting_index);\n __derive_generators(domain_separator_bytes, starting_index)\n}\n\n#[builtin(derive_pedersen_generators)]\n#[field(bn254)]\nfn __derive_generators<let N: u32, let M: u32>(\n domain_separator_bytes: [u8; M],\n starting_index: u32,\n) -> [EmbeddedCurvePoint; N] {}\n\n#[field(bn254)]\n// Decompose the input 'bn254 scalar' into two 128 bits limbs.\n// It is called 'unsafe' because it does not assert the limbs are 128 bits\n// Assuming the limbs are 128 bits:\n// Assert the decomposition does not overflow the field size.\nfn from_field_unsafe(scalar: Field) -> EmbeddedCurveScalar {\n // Safety: xlo and xhi decomposition is checked below\n let (xlo, xhi) = unsafe { crate::field::bn254::decompose_hint(scalar) };\n // Check that the decomposition is correct\n assert_eq(scalar, xlo + crate::field::bn254::TWO_POW_128 * xhi);\n // Check that the decomposition does not overflow the field size\n let (a, b) = if xhi == crate::field::bn254::PHI {\n (xlo, crate::field::bn254::PLO)\n } else {\n (xhi, crate::field::bn254::PHI)\n };\n crate::field::bn254::assert_lt(a, b);\n\n EmbeddedCurveScalar { lo: xlo, hi: xhi }\n}\n\npub fn poseidon2_permutation<let N: u32>(input: [Field; N]) -> [Field; N] {\n static_assert(\n N == POSEIDON2_CONFIG_STATE_SIZE,\n f\"the input length must equal the state size in the Poseidon2 config; expected {POSEIDON2_CONFIG_STATE_SIZE}, got {N}\",\n );\n poseidon2_permutation_internal(input)\n}\n\n#[foreign(poseidon2_permutation)]\nfn poseidon2_permutation_internal<let N: u32>(input: [Field; N]) -> [Field; N] {}\n\n#[foreign(poseidon2_config_state_size)]\ncomptime fn poseidon2_config_state_size() -> u32 {}\n\n// Generic hashing support.\n// Partially ported and impacted by rust.\n\n// Hash trait shall be implemented per type.\n#[derive_via(derive_hash)]\npub trait Hash {\n fn hash<H>(self, state: &mut H)\n where\n H: Hasher;\n}\n\n// docs:start:derive_hash\ncomptime fn derive_hash(s: TypeDefinition) -> Quoted {\n let name = quote { $crate::hash::Hash };\n let signature = quote { fn hash<H>(_self: Self, _state: &mut H) where H: $crate::hash::Hasher };\n let for_each_field = |name| quote { _self.$name.hash(_state); };\n crate::meta::make_trait_impl(\n s,\n name,\n signature,\n for_each_field,\n quote {},\n |fields| fields,\n )\n}\n// docs:end:derive_hash\n\n// Hasher trait shall be implemented by algorithms to provide hash-agnostic means.\n// TODO: consider making the types generic here ([u8], [Field], etc.)\npub trait Hasher {\n fn finish(self) -> Field;\n\n /// Returns the hash value without consuming the hasher.\n /// Override this for more efficient implementations that avoid copying.\n /// TODO: deprecate finish() and replace it\n fn finish_ref(&self) -> Field {\n (*self).finish()\n }\n\n fn write(&mut self, input: Field);\n}\n\n// BuildHasher is a factory trait, responsible for production of specific Hasher.\npub trait BuildHasher {\n type H: Hasher;\n\n fn build_hasher(self) -> H;\n}\n\npub struct BuildHasherDefault<H>;\n\nimpl<H> BuildHasher for BuildHasherDefault<H>\nwhere\n H: Hasher + Default,\n{\n type H = H;\n\n fn build_hasher(_self: Self) -> H {\n H::default()\n }\n}\n\nimpl<H> Default for BuildHasherDefault<H>\nwhere\n H: Hasher + Default,\n{\n fn default() -> Self {\n BuildHasherDefault {}\n }\n}\n\nimpl Hash for Field {\n fn hash<H>(self, state: &mut H)\n where\n H: Hasher,\n {\n H::write(state, self);\n }\n}\n\nimpl Hash for u8 {\n fn hash<H>(self, state: &mut H)\n where\n H: Hasher,\n {\n H::write(state, self as Field);\n }\n}\n\nimpl Hash for u16 {\n fn hash<H>(self, state: &mut H)\n where\n H: Hasher,\n {\n H::write(state, self as Field);\n }\n}\n\nimpl Hash for u32 {\n fn hash<H>(self, state: &mut H)\n where\n H: Hasher,\n {\n H::write(state, self as Field);\n }\n}\n\nimpl Hash for u64 {\n fn hash<H>(self, state: &mut H)\n where\n H: Hasher,\n {\n H::write(state, self as Field);\n }\n}\n\nimpl Hash for u128 {\n fn hash<H>(self, state: &mut H)\n where\n H: Hasher,\n {\n H::write(state, self as Field);\n }\n}\n\nimpl Hash for i8 {\n fn hash<H>(self, state: &mut H)\n where\n H: Hasher,\n {\n H::write(state, self as u8 as Field);\n }\n}\n\nimpl Hash for i16 {\n fn hash<H>(self, state: &mut H)\n where\n H: Hasher,\n {\n H::write(state, self as u16 as Field);\n }\n}\n\nimpl Hash for i32 {\n fn hash<H>(self, state: &mut H)\n where\n H: Hasher,\n {\n H::write(state, self as u32 as Field);\n }\n}\n\nimpl Hash for i64 {\n fn hash<H>(self, state: &mut H)\n where\n H: Hasher,\n {\n H::write(state, self as u64 as Field);\n }\n}\n\nimpl Hash for bool {\n fn hash<H>(self, state: &mut H)\n where\n H: Hasher,\n {\n H::write(state, self as Field);\n }\n}\n\nimpl Hash for () {\n fn hash<H>(_self: Self, _state: &mut H)\n where\n H: Hasher,\n {}\n}\n\nimpl<T, let N: u32> Hash for [T; N]\nwhere\n T: Hash,\n{\n fn hash<H>(self, state: &mut H)\n where\n H: Hasher,\n {\n for elem in self {\n elem.hash(state);\n }\n }\n}\n\nimpl<T> Hash for [T]\nwhere\n T: Hash,\n{\n fn hash<H>(self, state: &mut H)\n where\n H: Hasher,\n {\n self.len().hash(state);\n for elem in self {\n elem.hash(state);\n }\n }\n}\n\nimpl<A, B> Hash for (A, B)\nwhere\n A: Hash,\n B: Hash,\n{\n fn hash<H>(self, state: &mut H)\n where\n H: Hasher,\n {\n self.0.hash(state);\n self.1.hash(state);\n }\n}\n\nimpl<A, B, C> Hash for (A, B, C)\nwhere\n A: Hash,\n B: Hash,\n C: Hash,\n{\n fn hash<H>(self, state: &mut H)\n where\n H: Hasher,\n {\n self.0.hash(state);\n self.1.hash(state);\n self.2.hash(state);\n }\n}\n\nimpl<A, B, C, D> Hash for (A, B, C, D)\nwhere\n A: Hash,\n B: Hash,\n C: Hash,\n D: Hash,\n{\n fn hash<H>(self, state: &mut H)\n where\n H: Hasher,\n {\n self.0.hash(state);\n self.1.hash(state);\n self.2.hash(state);\n self.3.hash(state);\n }\n}\n\nimpl<A, B, C, D, E> Hash for (A, B, C, D, E)\nwhere\n A: Hash,\n B: Hash,\n C: Hash,\n D: Hash,\n E: Hash,\n{\n fn hash<H>(self, state: &mut H)\n where\n H: Hasher,\n {\n self.0.hash(state);\n self.1.hash(state);\n self.2.hash(state);\n self.3.hash(state);\n self.4.hash(state);\n }\n}\n\n// Some test vectors for Pedersen hash and Pedersen Commitment.\n// They have been generated using the same functions so the tests are for now useless\n// but they will be useful when we switch to Noir implementation.\n#[test]\nfn assert_pedersen() {\n assert_eq(\n pedersen_hash_with_separator([1], 1),\n 0x1b3f4b1a83092a13d8d1a59f7acb62aba15e7002f4440f2275edb99ebbc2305f,\n );\n assert_eq(\n pedersen_commitment_with_separator([1], 1),\n EmbeddedCurvePoint {\n x: 0x054aa86a73cb8a34525e5bbed6e43ba1198e860f5f3950268f71df4591bde402,\n y: 0x209dcfbf2cfb57f9f6046f44d71ac6faf87254afc7407c04eb621a6287cac126,\n },\n );\n\n assert_eq(\n pedersen_hash_with_separator([1, 2], 2),\n 0x26691c129448e9ace0c66d11f0a16d9014a9e8498ee78f4d69f0083168188255,\n );\n assert_eq(\n pedersen_commitment_with_separator([1, 2], 2),\n EmbeddedCurvePoint {\n x: 0x2e2b3b191e49541fe468ec6877721d445dcaffe41728df0a0eafeb15e87b0753,\n y: 0x2ff4482400ad3a6228be17a2af33e2bcdf41be04795f9782bd96efe7e24f8778,\n },\n );\n assert_eq(\n pedersen_hash_with_separator([1, 2, 3], 3),\n 0x0bc694b7a1f8d10d2d8987d07433f26bd616a2d351bc79a3c540d85b6206dbe4,\n );\n assert_eq(\n pedersen_commitment_with_separator([1, 2, 3], 3),\n EmbeddedCurvePoint {\n x: 0x1fee4e8cf8d2f527caa2684236b07c4b1bad7342c01b0f75e9a877a71827dc85,\n y: 0x2f9fedb9a090697ab69bf04c8bc15f7385b3e4b68c849c1536e5ae15ff138fd1,\n },\n );\n assert_eq(\n pedersen_hash_with_separator([1, 2, 3, 4], 4),\n 0xdae10fb32a8408521803905981a2b300d6a35e40e798743e9322b223a5eddc,\n );\n assert_eq(\n pedersen_commitment_with_separator([1, 2, 3, 4], 4),\n EmbeddedCurvePoint {\n x: 0x07ae3e202811e1fca39c2d81eabe6f79183978e6f12be0d3b8eda095b79bdbc9,\n y: 0x0afc6f892593db6fbba60f2da558517e279e0ae04f95758587760ba193145014,\n },\n );\n assert_eq(\n pedersen_hash_with_separator([1, 2, 3, 4, 5], 5),\n 0xfc375b062c4f4f0150f7100dfb8d9b72a6d28582dd9512390b0497cdad9c22,\n );\n assert_eq(\n pedersen_commitment_with_separator([1, 2, 3, 4, 5], 5),\n EmbeddedCurvePoint {\n x: 0x1754b12bd475a6984a1094b5109eeca9838f4f81ac89c5f0a41dbce53189bb29,\n y: 0x2da030e3cfcdc7ddad80eaf2599df6692cae0717d4e9f7bfbee8d073d5d278f7,\n },\n );\n assert_eq(\n pedersen_hash_with_separator([1, 2, 3, 4, 5, 6], 6),\n 0x1696ed13dc2730062a98ac9d8f9de0661bb98829c7582f699d0273b18c86a572,\n );\n assert_eq(\n pedersen_commitment_with_separator([1, 2, 3, 4, 5, 6], 6),\n EmbeddedCurvePoint {\n x: 0x190f6c0e97ad83e1e28da22a98aae156da083c5a4100e929b77e750d3106a697,\n y: 0x1f4b60f34ef91221a0b49756fa0705da93311a61af73d37a0c458877706616fb,\n },\n );\n assert_eq(\n pedersen_hash_with_separator([1, 2, 3, 4, 5, 6, 7], 7),\n 0x128c0ff144fc66b6cb60eeac8a38e23da52992fc427b92397a7dffd71c45ede3,\n );\n assert_eq(\n pedersen_commitment_with_separator([1, 2, 3, 4, 5, 6, 7], 7),\n EmbeddedCurvePoint {\n x: 0x015441e9d29491b06563fac16fc76abf7a9534c715421d0de85d20dbe2965939,\n y: 0x1d2575b0276f4e9087e6e07c2cb75aa1baafad127af4be5918ef8a2ef2fea8fc,\n },\n );\n assert_eq(\n pedersen_hash_with_separator([1, 2, 3, 4, 5, 6, 7, 8], 8),\n 0x2f960e117482044dfc99d12fece2ef6862fba9242be4846c7c9a3e854325a55c,\n );\n assert_eq(\n pedersen_commitment_with_separator([1, 2, 3, 4, 5, 6, 7, 8], 8),\n EmbeddedCurvePoint {\n x: 0x1657737676968887fceb6dd516382ea13b3a2c557f509811cd86d5d1199bc443,\n y: 0x1f39f0cb569040105fa1e2f156521e8b8e08261e635a2b210bdc94e8d6d65f77,\n },\n );\n assert_eq(\n pedersen_hash_with_separator([1, 2, 3, 4, 5, 6, 7, 8, 9], 9),\n 0x0c96db0790602dcb166cc4699e2d306c479a76926b81c2cb2aaa92d249ec7be7,\n );\n assert_eq(\n pedersen_commitment_with_separator([1, 2, 3, 4, 5, 6, 7, 8, 9], 9),\n EmbeddedCurvePoint {\n x: 0x0a3ceae42d14914a432aa60ec7fded4af7dad7dd4acdbf2908452675ec67e06d,\n y: 0xfc19761eaaf621ad4aec9a8b2e84a4eceffdba78f60f8b9391b0bd9345a2f2,\n },\n );\n assert_eq(\n pedersen_hash_with_separator([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 10),\n 0x2cd37505871bc460a62ea1e63c7fe51149df5d0801302cf1cbc48beb8dff7e94,\n );\n assert_eq(\n pedersen_commitment_with_separator([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 10),\n EmbeddedCurvePoint {\n x: 0x2fb3f8b3d41ddde007c8c3c62550f9a9380ee546fcc639ffbb3fd30c8d8de30c,\n y: 0x300783be23c446b11a4c0fabf6c91af148937cea15fcf5fb054abf7f752ee245,\n },\n );\n}\n"
4429
4425
  },
4430
4426
  "180": {
4431
4427
  "function_locations": [
@@ -4913,31 +4909,31 @@
4913
4909
  },
4914
4910
  {
4915
4911
  "name": "Poseidon2::absorb",
4916
- "start": 926
4912
+ "start": 923
4917
4913
  },
4918
4914
  {
4919
4915
  "name": "Poseidon2::squeeze",
4920
- "start": 1456
4916
+ "start": 1453
4921
4917
  },
4922
4918
  {
4923
4919
  "name": "Poseidon2::hash_internal",
4924
- "start": 1817
4920
+ "start": 1814
4925
4921
  },
4926
4922
  {
4927
4923
  "name": "<impl Hasher for Poseidon2Hasher>::finish",
4928
- "start": 4117
4924
+ "start": 4105
4929
4925
  },
4930
4926
  {
4931
4927
  "name": "<impl Hasher for Poseidon2Hasher>::write",
4932
- "start": 4438
4928
+ "start": 4426
4933
4929
  },
4934
4930
  {
4935
4931
  "name": "<impl Default for Poseidon2Hasher>::default",
4936
- "start": 4561
4932
+ "start": 4549
4937
4933
  }
4938
4934
  ],
4939
- "path": "/home/aztec-dev/nargo/github.com/noir-lang/poseidon/v0.2.6/src/poseidon2.nr",
4940
- "source": "use std::default::Default;\nuse std::hash::Hasher;\n\nglobal RATE: u32 = 3;\n\npub struct Poseidon2 {\n cache: [Field; 3],\n state: [Field; 4],\n cache_size: u32,\n squeeze_mode: bool, // 0 => absorb, 1 => squeeze\n}\n\nimpl Poseidon2 {\n #[no_predicates]\n pub fn hash<let N: u32>(input: [Field; N], message_size: u32) -> Field {\n Poseidon2::hash_internal(input, message_size)\n }\n\n pub(crate) fn new(iv: Field) -> Poseidon2 {\n let mut result =\n Poseidon2 { cache: [0; 3], state: [0; 4], cache_size: 0, squeeze_mode: false };\n result.state[RATE] = iv;\n result\n }\n\n fn perform_duplex(&mut self) {\n // add the cache into sponge state\n self.state[0] += self.cache[0];\n self.state[1] += self.cache[1];\n self.state[2] += self.cache[2];\n self.state = crate::poseidon2_permutation(self.state, 4);\n }\n\n fn absorb(&mut self, input: Field) {\n assert(!self.squeeze_mode);\n if self.cache_size == RATE {\n // If we're absorbing, and the cache is full, apply the sponge permutation to compress the cache\n self.perform_duplex();\n self.cache[0] = input;\n self.cache_size = 1;\n } else {\n // If we're absorbing, and the cache is not full, add the input into the cache\n self.cache[self.cache_size] = input;\n self.cache_size += 1;\n }\n }\n\n fn squeeze(&mut self) -> Field {\n assert(!self.squeeze_mode);\n // If we're in absorb mode, apply sponge permutation to compress the cache.\n self.perform_duplex();\n self.squeeze_mode = true;\n\n // Pop one item off the top of the permutation and return it.\n self.state[0]\n }\n\n fn hash_internal<let N: u32>(input: [Field; N], in_len: u32) -> Field {\n let two_pow_64 = 18446744073709551616;\n let iv: Field = (in_len as Field) * two_pow_64;\n let mut state = [0; 4];\n state[RATE] = iv;\n\n if std::runtime::is_unconstrained() {\n for i in 0..(in_len / RATE) {\n state[0] += input[i * RATE];\n state[1] += input[i * RATE + 1];\n state[2] += input[i * RATE + 2];\n state = crate::poseidon2_permutation(state, 4);\n }\n\n // handle remaining elements after last full RATE-sized chunk\n let num_extra_fields = in_len % RATE;\n if num_extra_fields != 0 {\n let remainder_start = in_len - num_extra_fields;\n state[0] += input[remainder_start];\n if num_extra_fields > 1 {\n state[1] += input[remainder_start + 1];\n }\n }\n } else {\n let mut states: [[Field; 4]; N / RATE + 1] = [[0; 4]; N / RATE + 1];\n states[0] = state;\n\n // process all full RATE-sized chunks, storing state after each permutation\n for chunk_idx in 0..(N / RATE) {\n for i in 0..RATE {\n state[i] += input[chunk_idx * RATE + i];\n }\n state = crate::poseidon2_permutation(state, 4);\n states[chunk_idx + 1] = state;\n }\n\n // get state at the last full block before in_len\n let first_partially_filled_chunk = in_len / RATE;\n state = states[first_partially_filled_chunk];\n\n // handle remaining elements after last full RATE-sized chunk\n let remainder_start = (in_len / RATE) * RATE;\n for j in 0..RATE {\n let idx = remainder_start + j;\n if idx < in_len {\n state[j] += input[idx];\n }\n }\n }\n\n // always run final permutation unless we just completed a full chunk\n // still need to permute once if in_len is 0\n if (in_len == 0) | (in_len % RATE != 0) {\n state = crate::poseidon2_permutation(state, 4);\n };\n\n state[0]\n }\n}\n\npub struct Poseidon2Hasher {\n _state: [Field],\n}\n\nimpl Hasher for Poseidon2Hasher {\n fn finish(self) -> Field {\n let iv: Field = (self._state.len() as Field) * 18446744073709551616; // iv = (self._state.len() << 64)\n let mut sponge = Poseidon2::new(iv);\n for i in 0..self._state.len() {\n sponge.absorb(self._state[i]);\n }\n sponge.squeeze()\n }\n\n fn write(&mut self, input: Field) {\n self._state = self._state.push_back(input);\n }\n}\n\nimpl Default for Poseidon2Hasher {\n fn default() -> Self {\n Poseidon2Hasher { _state: &[] }\n }\n}\n"
4935
+ "path": "/home/aztec-dev/nargo/github.com/noir-lang/poseidon/v0.3.0/src/poseidon2.nr",
4936
+ "source": "use std::default::Default;\nuse std::hash::Hasher;\n\nglobal RATE: u32 = 3;\n\npub struct Poseidon2 {\n cache: [Field; 3],\n state: [Field; 4],\n cache_size: u32,\n squeeze_mode: bool, // 0 => absorb, 1 => squeeze\n}\n\nimpl Poseidon2 {\n #[no_predicates]\n pub fn hash<let N: u32>(input: [Field; N], message_size: u32) -> Field {\n Poseidon2::hash_internal(input, message_size)\n }\n\n pub(crate) fn new(iv: Field) -> Poseidon2 {\n let mut result =\n Poseidon2 { cache: [0; 3], state: [0; 4], cache_size: 0, squeeze_mode: false };\n result.state[RATE] = iv;\n result\n }\n\n fn perform_duplex(&mut self) {\n // add the cache into sponge state\n self.state[0] += self.cache[0];\n self.state[1] += self.cache[1];\n self.state[2] += self.cache[2];\n self.state = crate::poseidon2_permutation(self.state);\n }\n\n fn absorb(&mut self, input: Field) {\n assert(!self.squeeze_mode);\n if self.cache_size == RATE {\n // If we're absorbing, and the cache is full, apply the sponge permutation to compress the cache\n self.perform_duplex();\n self.cache[0] = input;\n self.cache_size = 1;\n } else {\n // If we're absorbing, and the cache is not full, add the input into the cache\n self.cache[self.cache_size] = input;\n self.cache_size += 1;\n }\n }\n\n fn squeeze(&mut self) -> Field {\n assert(!self.squeeze_mode);\n // If we're in absorb mode, apply sponge permutation to compress the cache.\n self.perform_duplex();\n self.squeeze_mode = true;\n\n // Pop one item off the top of the permutation and return it.\n self.state[0]\n }\n\n fn hash_internal<let N: u32>(input: [Field; N], in_len: u32) -> Field {\n let two_pow_64 = 18446744073709551616;\n let iv: Field = (in_len as Field) * two_pow_64;\n let mut state = [0; 4];\n state[RATE] = iv;\n\n if std::runtime::is_unconstrained() {\n for i in 0..(in_len / RATE) {\n state[0] += input[i * RATE];\n state[1] += input[i * RATE + 1];\n state[2] += input[i * RATE + 2];\n state = crate::poseidon2_permutation(state);\n }\n\n // handle remaining elements after last full RATE-sized chunk\n let num_extra_fields = in_len % RATE;\n if num_extra_fields != 0 {\n let remainder_start = in_len - num_extra_fields;\n state[0] += input[remainder_start];\n if num_extra_fields > 1 {\n state[1] += input[remainder_start + 1];\n }\n }\n } else {\n let mut states: [[Field; 4]; N / RATE + 1] = [[0; 4]; N / RATE + 1];\n states[0] = state;\n\n // process all full RATE-sized chunks, storing state after each permutation\n for chunk_idx in 0..(N / RATE) {\n for i in 0..RATE {\n state[i] += input[chunk_idx * RATE + i];\n }\n state = crate::poseidon2_permutation(state);\n states[chunk_idx + 1] = state;\n }\n\n // get state at the last full block before in_len\n let first_partially_filled_chunk = in_len / RATE;\n state = states[first_partially_filled_chunk];\n\n // handle remaining elements after last full RATE-sized chunk\n let remainder_start = (in_len / RATE) * RATE;\n for j in 0..RATE {\n let idx = remainder_start + j;\n if idx < in_len {\n state[j] += input[idx];\n }\n }\n }\n\n // always run final permutation unless we just completed a full chunk\n // still need to permute once if in_len is 0\n if (in_len == 0) | (in_len % RATE != 0) {\n state = crate::poseidon2_permutation(state);\n };\n\n state[0]\n }\n}\n\npub struct Poseidon2Hasher {\n _state: [Field],\n}\n\nimpl Hasher for Poseidon2Hasher {\n fn finish(self) -> Field {\n let iv: Field = (self._state.len() as Field) * 18446744073709551616; // iv = (self._state.len() << 64)\n let mut sponge = Poseidon2::new(iv);\n for i in 0..self._state.len() {\n sponge.absorb(self._state[i]);\n }\n sponge.squeeze()\n }\n\n fn write(&mut self, input: Field) {\n self._state = self._state.push_back(input);\n }\n}\n\nimpl Default for Poseidon2Hasher {\n fn default() -> Self {\n Poseidon2Hasher { _state: @[] }\n }\n}\n"
4941
4937
  },
4942
4938
  "277": {
4943
4939
  "function_locations": [
@@ -5335,19 +5331,19 @@
5335
5331
  },
5336
5332
  {
5337
5333
  "name": "Poseidon2Sponge::absorb",
5338
- "start": 1595
5334
+ "start": 1592
5339
5335
  },
5340
5336
  {
5341
5337
  "name": "Poseidon2Sponge::squeeze",
5342
- "start": 2129
5338
+ "start": 2126
5343
5339
  },
5344
5340
  {
5345
5341
  "name": "Poseidon2Sponge::hash_internal",
5346
- "start": 2547
5342
+ "start": 2544
5347
5343
  }
5348
5344
  ],
5349
5345
  "path": "/home/aztec-dev/aztec-packages/noir-projects/noir-protocol-circuits/crates/types/src/poseidon2.nr",
5350
- "source": "use crate::constants::TWO_POW_64;\nuse crate::traits::{Deserialize, Serialize};\nuse std::meta::derive;\n// NB: This is a clone of noir/noir-repo/noir_stdlib/src/hash/poseidon2.nr\n// It exists as we sometimes need to perform custom absorption, but the stdlib version\n// has a private absorb() method (it's also designed to just be a hasher)\n// Can be removed when standalone noir poseidon lib exists: See noir#6679\n// TODO: Poseidon is stand-alone now\n\nglobal RATE: u32 = 3;\n\n#[derive(Deserialize, Eq, Serialize)]\npub struct Poseidon2Sponge {\n pub cache: [Field; 3],\n pub state: [Field; 4],\n pub cache_size: u32,\n pub squeeze_mode: bool, // 0 => absorb, 1 => squeeze\n}\n\nimpl Poseidon2Sponge {\n #[no_predicates]\n pub fn hash<let N: u32>(input: [Field; N], message_size: u32) -> Field {\n Poseidon2Sponge::hash_internal(input, message_size, message_size != N)\n }\n\n pub(crate) fn new(iv: Field) -> Poseidon2Sponge {\n let mut result =\n Poseidon2Sponge { cache: [0; 3], state: [0; 4], cache_size: 0, squeeze_mode: false };\n result.state[RATE] = iv;\n result\n }\n\n fn perform_duplex(&mut self) {\n // add the cache into sponge state\n for i in 0..RATE {\n // We effectively zero-pad the cache by only adding to the state\n // cache that is less than the specified `cache_size`\n if i < self.cache_size {\n self.state[i] += self.cache[i];\n }\n }\n self.state = std::hash::poseidon2_permutation(self.state, 4);\n }\n\n pub fn absorb(&mut self, input: Field) {\n assert(!self.squeeze_mode);\n if self.cache_size == RATE {\n // If we're absorbing, and the cache is full, apply the sponge permutation to compress the cache\n self.perform_duplex();\n self.cache[0] = input;\n self.cache_size = 1;\n } else {\n // If we're absorbing, and the cache is not full, add the input into the cache\n self.cache[self.cache_size] = input;\n self.cache_size += 1;\n }\n }\n\n pub fn squeeze(&mut self) -> Field {\n assert(!self.squeeze_mode);\n // If we're in absorb mode, apply sponge permutation to compress the cache.\n self.perform_duplex();\n self.squeeze_mode = true;\n\n // Pop one item off the top of the permutation and return it.\n self.state[0]\n }\n\n fn hash_internal<let N: u32>(\n input: [Field; N],\n in_len: u32,\n is_variable_length: bool,\n ) -> Field {\n let iv: Field = (in_len as Field) * TWO_POW_64;\n let mut sponge = Poseidon2Sponge::new(iv);\n for i in 0..input.len() {\n if i < in_len {\n sponge.absorb(input[i]);\n }\n }\n\n sponge.squeeze()\n }\n}\n"
5346
+ "source": "use crate::constants::TWO_POW_64;\nuse crate::traits::{Deserialize, Serialize};\nuse std::meta::derive;\n// NB: This is a clone of noir/noir-repo/noir_stdlib/src/hash/poseidon2.nr\n// It exists as we sometimes need to perform custom absorption, but the stdlib version\n// has a private absorb() method (it's also designed to just be a hasher)\n// Can be removed when standalone noir poseidon lib exists: See noir#6679\n// TODO: Poseidon is stand-alone now\n\nglobal RATE: u32 = 3;\n\n#[derive(Deserialize, Eq, Serialize)]\npub struct Poseidon2Sponge {\n pub cache: [Field; 3],\n pub state: [Field; 4],\n pub cache_size: u32,\n pub squeeze_mode: bool, // 0 => absorb, 1 => squeeze\n}\n\nimpl Poseidon2Sponge {\n #[no_predicates]\n pub fn hash<let N: u32>(input: [Field; N], message_size: u32) -> Field {\n Poseidon2Sponge::hash_internal(input, message_size, message_size != N)\n }\n\n pub(crate) fn new(iv: Field) -> Poseidon2Sponge {\n let mut result =\n Poseidon2Sponge { cache: [0; 3], state: [0; 4], cache_size: 0, squeeze_mode: false };\n result.state[RATE] = iv;\n result\n }\n\n fn perform_duplex(&mut self) {\n // add the cache into sponge state\n for i in 0..RATE {\n // We effectively zero-pad the cache by only adding to the state\n // cache that is less than the specified `cache_size`\n if i < self.cache_size {\n self.state[i] += self.cache[i];\n }\n }\n self.state = std::hash::poseidon2_permutation(self.state);\n }\n\n pub fn absorb(&mut self, input: Field) {\n assert(!self.squeeze_mode);\n if self.cache_size == RATE {\n // If we're absorbing, and the cache is full, apply the sponge permutation to compress the cache\n self.perform_duplex();\n self.cache[0] = input;\n self.cache_size = 1;\n } else {\n // If we're absorbing, and the cache is not full, add the input into the cache\n self.cache[self.cache_size] = input;\n self.cache_size += 1;\n }\n }\n\n pub fn squeeze(&mut self) -> Field {\n assert(!self.squeeze_mode);\n // If we're in absorb mode, apply sponge permutation to compress the cache.\n self.perform_duplex();\n self.squeeze_mode = true;\n\n // Pop one item off the top of the permutation and return it.\n self.state[0]\n }\n\n fn hash_internal<let N: u32>(\n input: [Field; N],\n in_len: u32,\n is_variable_length: bool,\n ) -> Field {\n let iv: Field = (in_len as Field) * TWO_POW_64;\n let mut sponge = Poseidon2Sponge::new(iv);\n for i in 0..input.len() {\n if i < in_len {\n sponge.absorb(input[i]);\n }\n }\n\n sponge.squeeze()\n }\n}\n"
5351
5347
  },
5352
5348
  "388": {
5353
5349
  "function_locations": [
@@ -5373,37 +5369,33 @@
5373
5369
  "name": "<impl ToField for bool>::to_field",
5374
5370
  "start": 276
5375
5371
  },
5376
- {
5377
- "name": "<impl ToField for u1>::to_field",
5378
- "start": 382
5379
- },
5380
5372
  {
5381
5373
  "name": "<impl ToField for u8>::to_field",
5382
- "start": 488
5374
+ "start": 382
5383
5375
  },
5384
5376
  {
5385
5377
  "name": "<impl ToField for u16>::to_field",
5386
- "start": 574
5378
+ "start": 468
5387
5379
  },
5388
5380
  {
5389
5381
  "name": "<impl ToField for u32>::to_field",
5390
- "start": 681
5382
+ "start": 575
5391
5383
  },
5392
5384
  {
5393
5385
  "name": "<impl ToField for u64>::to_field",
5394
- "start": 788
5386
+ "start": 682
5395
5387
  },
5396
5388
  {
5397
5389
  "name": "<impl ToField for u128>::to_field",
5398
- "start": 896
5390
+ "start": 790
5399
5391
  },
5400
5392
  {
5401
5393
  "name": "<impl ToField for str<N>>::to_field",
5402
- "start": 1018
5394
+ "start": 912
5403
5395
  }
5404
5396
  ],
5405
5397
  "path": "/home/aztec-dev/aztec-packages/noir-projects/noir-protocol-circuits/crates/types/src/traits/to_field.nr",
5406
- "source": "use crate::utils::field::field_from_bytes;\n\npub trait ToField {\n fn to_field(self) -> Field;\n}\n\nimpl ToField for Field {\n #[inline_always]\n fn to_field(self) -> Field {\n self\n }\n}\n\nimpl ToField for bool {\n #[inline_always]\n fn to_field(self) -> Field {\n self as Field\n }\n}\nimpl ToField for u1 {\n #[inline_always]\n fn to_field(self) -> Field {\n self as Field\n }\n}\nimpl ToField for u8 {\n #[inline_always]\n fn to_field(self) -> Field {\n self as Field\n }\n}\nimpl ToField for u16 {\n fn to_field(self) -> Field {\n self as Field\n }\n}\nimpl ToField for u32 {\n #[inline_always]\n fn to_field(self) -> Field {\n self as Field\n }\n}\nimpl ToField for u64 {\n #[inline_always]\n fn to_field(self) -> Field {\n self as Field\n }\n}\nimpl ToField for u128 {\n #[inline_always]\n fn to_field(self) -> Field {\n self as Field\n }\n}\nimpl<let N: u32> ToField for str<N> {\n #[inline_always]\n fn to_field(self) -> Field {\n assert(N < 32, \"String doesn't fit in a field, consider using Serialize instead\");\n field_from_bytes(self.as_bytes(), true)\n }\n}\n"
5398
+ "source": "use crate::utils::field::field_from_bytes;\n\npub trait ToField {\n fn to_field(self) -> Field;\n}\n\nimpl ToField for Field {\n #[inline_always]\n fn to_field(self) -> Field {\n self\n }\n}\n\nimpl ToField for bool {\n #[inline_always]\n fn to_field(self) -> Field {\n self as Field\n }\n}\nimpl ToField for u8 {\n #[inline_always]\n fn to_field(self) -> Field {\n self as Field\n }\n}\nimpl ToField for u16 {\n fn to_field(self) -> Field {\n self as Field\n }\n}\nimpl ToField for u32 {\n #[inline_always]\n fn to_field(self) -> Field {\n self as Field\n }\n}\nimpl ToField for u64 {\n #[inline_always]\n fn to_field(self) -> Field {\n self as Field\n }\n}\nimpl ToField for u128 {\n #[inline_always]\n fn to_field(self) -> Field {\n self as Field\n }\n}\nimpl<let N: u32> ToField for str<N> {\n #[inline_always]\n fn to_field(self) -> Field {\n assert(N < 32, \"String doesn't fit in a field, consider using Serialize instead\");\n field_from_bytes(self.as_bytes(), true)\n }\n}\n"
5407
5399
  },
5408
5400
  "396": {
5409
5401
  "function_locations": [
@@ -5417,115 +5409,115 @@
5417
5409
  },
5418
5410
  {
5419
5411
  "name": "<impl Packable for u8>::pack",
5420
- "start": 763
5412
+ "start": 767
5421
5413
  },
5422
5414
  {
5423
5415
  "name": "<impl Packable for u8>::unpack",
5424
- "start": 865
5416
+ "start": 869
5425
5417
  },
5426
5418
  {
5427
5419
  "name": "<impl Packable for u16>::pack",
5428
- "start": 1017
5420
+ "start": 1021
5429
5421
  },
5430
5422
  {
5431
5423
  "name": "<impl Packable for u16>::unpack",
5432
- "start": 1119
5424
+ "start": 1123
5433
5425
  },
5434
5426
  {
5435
5427
  "name": "<impl Packable for u32>::pack",
5436
- "start": 1272
5428
+ "start": 1276
5437
5429
  },
5438
5430
  {
5439
5431
  "name": "<impl Packable for u32>::unpack",
5440
- "start": 1374
5432
+ "start": 1378
5441
5433
  },
5442
5434
  {
5443
5435
  "name": "<impl Packable for u64>::pack",
5444
- "start": 1527
5436
+ "start": 1531
5445
5437
  },
5446
5438
  {
5447
5439
  "name": "<impl Packable for u64>::unpack",
5448
- "start": 1629
5440
+ "start": 1633
5449
5441
  },
5450
5442
  {
5451
5443
  "name": "<impl Packable for u128>::pack",
5452
- "start": 1784
5444
+ "start": 1788
5453
5445
  },
5454
5446
  {
5455
5447
  "name": "<impl Packable for u128>::unpack",
5456
- "start": 1886
5448
+ "start": 1890
5457
5449
  },
5458
5450
  {
5459
5451
  "name": "<impl Packable for Field>::pack",
5460
- "start": 2044
5452
+ "start": 2048
5461
5453
  },
5462
5454
  {
5463
5455
  "name": "<impl Packable for Field>::unpack",
5464
- "start": 2137
5456
+ "start": 2141
5465
5457
  },
5466
5458
  {
5467
5459
  "name": "<impl Packable for i8>::pack",
5468
- "start": 2281
5460
+ "start": 2285
5469
5461
  },
5470
5462
  {
5471
5463
  "name": "<impl Packable for i8>::unpack",
5472
- "start": 2389
5464
+ "start": 2393
5473
5465
  },
5474
5466
  {
5475
5467
  "name": "<impl Packable for i16>::pack",
5476
- "start": 2547
5468
+ "start": 2551
5477
5469
  },
5478
5470
  {
5479
5471
  "name": "<impl Packable for i16>::unpack",
5480
- "start": 2656
5472
+ "start": 2660
5481
5473
  },
5482
5474
  {
5483
5475
  "name": "<impl Packable for i32>::pack",
5484
- "start": 2816
5476
+ "start": 2820
5485
5477
  },
5486
5478
  {
5487
5479
  "name": "<impl Packable for i32>::unpack",
5488
- "start": 2925
5480
+ "start": 2929
5489
5481
  },
5490
5482
  {
5491
5483
  "name": "<impl Packable for i64>::pack",
5492
- "start": 3085
5484
+ "start": 3089
5493
5485
  },
5494
5486
  {
5495
5487
  "name": "<impl Packable for i64>::unpack",
5496
- "start": 3194
5488
+ "start": 3198
5497
5489
  },
5498
5490
  {
5499
5491
  "name": "<impl Packable for [T; M]>::pack",
5500
- "start": 3403
5492
+ "start": 3407
5501
5493
  },
5502
5494
  {
5503
5495
  "name": "<impl Packable for [T; M]>::unpack",
5504
- "start": 3765
5496
+ "start": 3769
5505
5497
  },
5506
5498
  {
5507
5499
  "name": "test_u16_packing",
5508
- "start": 4010
5500
+ "start": 4014
5509
5501
  },
5510
5502
  {
5511
5503
  "name": "test_i8_packing",
5512
- "start": 4106
5504
+ "start": 4110
5513
5505
  },
5514
5506
  {
5515
5507
  "name": "test_i16_packing",
5516
- "start": 4202
5508
+ "start": 4206
5517
5509
  },
5518
5510
  {
5519
5511
  "name": "test_i32_packing",
5520
- "start": 4300
5512
+ "start": 4304
5521
5513
  },
5522
5514
  {
5523
5515
  "name": "test_i64_packing",
5524
- "start": 4398
5516
+ "start": 4402
5525
5517
  }
5526
5518
  ],
5527
5519
  "path": "/home/aztec-dev/aztec-packages/noir-projects/noir-protocol-circuits/crates/types/src/type_packing.nr",
5528
- "source": "use crate::traits::Packable;\n\nglobal BOOL_PACKED_LEN: u32 = 1;\nglobal U8_PACKED_LEN: u32 = 1;\nglobal U16_PACKED_LEN: u32 = 1;\nglobal U32_PACKED_LEN: u32 = 1;\nglobal U64_PACKED_LEN: u32 = 1;\nglobal U128_PACKED_LEN: u32 = 1;\nglobal FIELD_PACKED_LEN: u32 = 1;\nglobal I8_PACKED_LEN: u32 = 1;\nglobal I16_PACKED_LEN: u32 = 1;\nglobal I32_PACKED_LEN: u32 = 1;\nglobal I64_PACKED_LEN: u32 = 1;\n\nimpl Packable for bool {\n let N: u32 = BOOL_PACKED_LEN;\n\n #[inline_always]\n fn pack(self) -> [Field; Self::N] {\n [self as Field]\n }\n\n #[inline_always]\n fn unpack(fields: [Field; Self::N]) -> bool {\n (fields[0] as u1) != 0\n }\n}\n\nimpl Packable for u8 {\n let N: u32 = U8_PACKED_LEN;\n\n #[inline_always]\n fn pack(self) -> [Field; Self::N] {\n [self as Field]\n }\n\n #[inline_always]\n fn unpack(fields: [Field; Self::N]) -> Self {\n fields[0] as u8\n }\n}\n\nimpl Packable for u16 {\n let N: u32 = U16_PACKED_LEN;\n\n #[inline_always]\n fn pack(self) -> [Field; Self::N] {\n [self as Field]\n }\n\n #[inline_always]\n fn unpack(fields: [Field; Self::N]) -> Self {\n fields[0] as u16\n }\n}\n\nimpl Packable for u32 {\n let N: u32 = U32_PACKED_LEN;\n\n #[inline_always]\n fn pack(self) -> [Field; Self::N] {\n [self as Field]\n }\n\n #[inline_always]\n fn unpack(fields: [Field; Self::N]) -> Self {\n fields[0] as u32\n }\n}\n\nimpl Packable for u64 {\n let N: u32 = U64_PACKED_LEN;\n\n #[inline_always]\n fn pack(self) -> [Field; Self::N] {\n [self as Field]\n }\n\n #[inline_always]\n fn unpack(fields: [Field; Self::N]) -> Self {\n fields[0] as u64\n }\n}\n\nimpl Packable for u128 {\n let N: u32 = U128_PACKED_LEN;\n\n #[inline_always]\n fn pack(self) -> [Field; Self::N] {\n [self as Field]\n }\n\n #[inline_always]\n fn unpack(fields: [Field; Self::N]) -> Self {\n fields[0] as u128\n }\n}\n\nimpl Packable for Field {\n let N: u32 = FIELD_PACKED_LEN;\n\n #[inline_always]\n fn pack(self) -> [Field; Self::N] {\n [self]\n }\n\n #[inline_always]\n fn unpack(fields: [Field; Self::N]) -> Self {\n fields[0]\n }\n}\n\nimpl Packable for i8 {\n let N: u32 = I8_PACKED_LEN;\n\n #[inline_always]\n fn pack(self) -> [Field; Self::N] {\n [self as u8 as Field]\n }\n\n #[inline_always]\n fn unpack(fields: [Field; Self::N]) -> Self {\n fields[0] as u8 as i8\n }\n}\n\nimpl Packable for i16 {\n let N: u32 = I16_PACKED_LEN;\n\n #[inline_always]\n fn pack(self) -> [Field; Self::N] {\n [self as u16 as Field]\n }\n\n #[inline_always]\n fn unpack(fields: [Field; Self::N]) -> Self {\n fields[0] as u16 as i16\n }\n}\n\nimpl Packable for i32 {\n let N: u32 = I32_PACKED_LEN;\n\n #[inline_always]\n fn pack(self) -> [Field; Self::N] {\n [self as u32 as Field]\n }\n\n #[inline_always]\n fn unpack(fields: [Field; Self::N]) -> Self {\n fields[0] as u32 as i32\n }\n}\n\nimpl Packable for i64 {\n let N: u32 = I64_PACKED_LEN;\n\n #[inline_always]\n fn pack(self) -> [Field; Self::N] {\n [self as u64 as Field]\n }\n\n #[inline_always]\n fn unpack(fields: [Field; Self::N]) -> Self {\n fields[0] as u64 as i64\n }\n}\n\nimpl<T, let M: u32> Packable for [T; M]\nwhere\n T: Packable,\n{\n let N: u32 = M * <T as Packable>::N;\n\n #[inline_always]\n fn pack(self) -> [Field; Self::N] {\n let mut result: [Field; Self::N] = std::mem::zeroed();\n for i in 0..M {\n let serialized = self[i].pack();\n for j in 0..<T as Packable>::N {\n result[i * <T as Packable>::N + j] = serialized[j];\n }\n }\n result\n }\n\n #[inline_always]\n fn unpack(fields: [Field; Self::N]) -> Self {\n let mut reader = crate::utils::reader::Reader::new(fields);\n let result: [T; M] = std::mem::zeroed();\n reader.read_struct_array::<T, <T as Packable>::N, M>(Packable::unpack, result)\n }\n}\n\n#[test]\nfn test_u16_packing() {\n let a: u16 = 10;\n assert_eq(a, u16::unpack(a.pack()));\n}\n\n#[test]\nfn test_i8_packing() {\n let a: i8 = -10;\n assert_eq(a, i8::unpack(a.pack()));\n}\n\n#[test]\nfn test_i16_packing() {\n let a: i16 = -10;\n assert_eq(a, i16::unpack(a.pack()));\n}\n\n#[test]\nfn test_i32_packing() {\n let a: i32 = -10;\n assert_eq(a, i32::unpack(a.pack()));\n}\n\n#[test]\nfn test_i64_packing() {\n let a: i64 = -10;\n assert_eq(a, i64::unpack(a.pack()));\n}\n"
5520
+ "source": "use crate::traits::Packable;\n\nglobal BOOL_PACKED_LEN: u32 = 1;\nglobal U8_PACKED_LEN: u32 = 1;\nglobal U16_PACKED_LEN: u32 = 1;\nglobal U32_PACKED_LEN: u32 = 1;\nglobal U64_PACKED_LEN: u32 = 1;\nglobal U128_PACKED_LEN: u32 = 1;\nglobal FIELD_PACKED_LEN: u32 = 1;\nglobal I8_PACKED_LEN: u32 = 1;\nglobal I16_PACKED_LEN: u32 = 1;\nglobal I32_PACKED_LEN: u32 = 1;\nglobal I64_PACKED_LEN: u32 = 1;\n\nimpl Packable for bool {\n let N: u32 = BOOL_PACKED_LEN;\n\n #[inline_always]\n fn pack(self) -> [Field; Self::N] {\n [self as Field]\n }\n\n #[inline_always]\n fn unpack(fields: [Field; Self::N]) -> bool {\n (fields[0] as u8) % 2 != 0\n }\n}\n\nimpl Packable for u8 {\n let N: u32 = U8_PACKED_LEN;\n\n #[inline_always]\n fn pack(self) -> [Field; Self::N] {\n [self as Field]\n }\n\n #[inline_always]\n fn unpack(fields: [Field; Self::N]) -> Self {\n fields[0] as u8\n }\n}\n\nimpl Packable for u16 {\n let N: u32 = U16_PACKED_LEN;\n\n #[inline_always]\n fn pack(self) -> [Field; Self::N] {\n [self as Field]\n }\n\n #[inline_always]\n fn unpack(fields: [Field; Self::N]) -> Self {\n fields[0] as u16\n }\n}\n\nimpl Packable for u32 {\n let N: u32 = U32_PACKED_LEN;\n\n #[inline_always]\n fn pack(self) -> [Field; Self::N] {\n [self as Field]\n }\n\n #[inline_always]\n fn unpack(fields: [Field; Self::N]) -> Self {\n fields[0] as u32\n }\n}\n\nimpl Packable for u64 {\n let N: u32 = U64_PACKED_LEN;\n\n #[inline_always]\n fn pack(self) -> [Field; Self::N] {\n [self as Field]\n }\n\n #[inline_always]\n fn unpack(fields: [Field; Self::N]) -> Self {\n fields[0] as u64\n }\n}\n\nimpl Packable for u128 {\n let N: u32 = U128_PACKED_LEN;\n\n #[inline_always]\n fn pack(self) -> [Field; Self::N] {\n [self as Field]\n }\n\n #[inline_always]\n fn unpack(fields: [Field; Self::N]) -> Self {\n fields[0] as u128\n }\n}\n\nimpl Packable for Field {\n let N: u32 = FIELD_PACKED_LEN;\n\n #[inline_always]\n fn pack(self) -> [Field; Self::N] {\n [self]\n }\n\n #[inline_always]\n fn unpack(fields: [Field; Self::N]) -> Self {\n fields[0]\n }\n}\n\nimpl Packable for i8 {\n let N: u32 = I8_PACKED_LEN;\n\n #[inline_always]\n fn pack(self) -> [Field; Self::N] {\n [self as u8 as Field]\n }\n\n #[inline_always]\n fn unpack(fields: [Field; Self::N]) -> Self {\n fields[0] as u8 as i8\n }\n}\n\nimpl Packable for i16 {\n let N: u32 = I16_PACKED_LEN;\n\n #[inline_always]\n fn pack(self) -> [Field; Self::N] {\n [self as u16 as Field]\n }\n\n #[inline_always]\n fn unpack(fields: [Field; Self::N]) -> Self {\n fields[0] as u16 as i16\n }\n}\n\nimpl Packable for i32 {\n let N: u32 = I32_PACKED_LEN;\n\n #[inline_always]\n fn pack(self) -> [Field; Self::N] {\n [self as u32 as Field]\n }\n\n #[inline_always]\n fn unpack(fields: [Field; Self::N]) -> Self {\n fields[0] as u32 as i32\n }\n}\n\nimpl Packable for i64 {\n let N: u32 = I64_PACKED_LEN;\n\n #[inline_always]\n fn pack(self) -> [Field; Self::N] {\n [self as u64 as Field]\n }\n\n #[inline_always]\n fn unpack(fields: [Field; Self::N]) -> Self {\n fields[0] as u64 as i64\n }\n}\n\nimpl<T, let M: u32> Packable for [T; M]\nwhere\n T: Packable,\n{\n let N: u32 = M * <T as Packable>::N;\n\n #[inline_always]\n fn pack(self) -> [Field; Self::N] {\n let mut result: [Field; Self::N] = std::mem::zeroed();\n for i in 0..M {\n let serialized = self[i].pack();\n for j in 0..<T as Packable>::N {\n result[i * <T as Packable>::N + j] = serialized[j];\n }\n }\n result\n }\n\n #[inline_always]\n fn unpack(fields: [Field; Self::N]) -> Self {\n let mut reader = crate::utils::reader::Reader::new(fields);\n let result: [T; M] = std::mem::zeroed();\n reader.read_struct_array::<T, <T as Packable>::N, M>(Packable::unpack, result)\n }\n}\n\n#[test]\nfn test_u16_packing() {\n let a: u16 = 10;\n assert_eq(a, u16::unpack(a.pack()));\n}\n\n#[test]\nfn test_i8_packing() {\n let a: i8 = -10;\n assert_eq(a, i8::unpack(a.pack()));\n}\n\n#[test]\nfn test_i16_packing() {\n let a: i16 = -10;\n assert_eq(a, i16::unpack(a.pack()));\n}\n\n#[test]\nfn test_i32_packing() {\n let a: i32 = -10;\n assert_eq(a, i32::unpack(a.pack()));\n}\n\n#[test]\nfn test_i64_packing() {\n let a: i64 = -10;\n assert_eq(a, i64::unpack(a.pack()));\n}\n"
5529
5521
  },
5530
5522
  "403": {
5531
5523
  "function_locations": [
@@ -5547,99 +5539,99 @@
5547
5539
  },
5548
5540
  {
5549
5541
  "name": "sqrt",
5550
- "start": 2231
5542
+ "start": 2233
5551
5543
  },
5552
5544
  {
5553
5545
  "name": "is_square",
5554
- "start": 2913
5546
+ "start": 2915
5555
5547
  },
5556
5548
  {
5557
5549
  "name": "tonelli_shanks_sqrt",
5558
- "start": 3341
5550
+ "start": 3343
5559
5551
  },
5560
5552
  {
5561
5553
  "name": "__sqrt",
5562
- "start": 3949
5554
+ "start": 3951
5563
5555
  },
5564
5556
  {
5565
5557
  "name": "validate_sqrt_hint",
5566
- "start": 4793
5558
+ "start": 4795
5567
5559
  },
5568
5560
  {
5569
5561
  "name": "validate_not_sqrt_hint",
5570
- "start": 4930
5562
+ "start": 4932
5571
5563
  },
5572
5564
  {
5573
5565
  "name": "bytes_field_test",
5574
- "start": 6568
5566
+ "start": 6570
5575
5567
  },
5576
5568
  {
5577
5569
  "name": "max_field_test",
5578
- "start": 7551
5570
+ "start": 7553
5579
5571
  },
5580
5572
  {
5581
5573
  "name": "sqrt_valid_test",
5582
- "start": 8175
5574
+ "start": 8177
5583
5575
  },
5584
5576
  {
5585
5577
  "name": "sqrt_invalid_test",
5586
- "start": 8377
5578
+ "start": 8379
5587
5579
  },
5588
5580
  {
5589
5581
  "name": "sqrt_zero_test",
5590
- "start": 8546
5582
+ "start": 8548
5591
5583
  },
5592
5584
  {
5593
5585
  "name": "sqrt_one_test",
5594
- "start": 8683
5586
+ "start": 8685
5595
5587
  },
5596
5588
  {
5597
5589
  "name": "field_from_bytes_empty_test",
5598
- "start": 8852
5590
+ "start": 8854
5599
5591
  },
5600
5592
  {
5601
5593
  "name": "field_from_bytes_little_endian_test",
5602
- "start": 9105
5594
+ "start": 9107
5603
5595
  },
5604
5596
  {
5605
5597
  "name": "pow_test",
5606
- "start": 9490
5598
+ "start": 9492
5607
5599
  },
5608
5600
  {
5609
5601
  "name": "min_test",
5610
- "start": 9713
5602
+ "start": 9715
5611
5603
  },
5612
5604
  {
5613
5605
  "name": "sqrt_has_two_roots_test",
5614
- "start": 9887
5606
+ "start": 9889
5615
5607
  },
5616
5608
  {
5617
5609
  "name": "sqrt_negative_one_test",
5618
- "start": 10560
5610
+ "start": 10562
5619
5611
  },
5620
5612
  {
5621
5613
  "name": "validate_sqrt_hint_valid_test",
5622
- "start": 10766
5614
+ "start": 10768
5623
5615
  },
5624
5616
  {
5625
5617
  "name": "validate_sqrt_hint_invalid_test",
5626
- "start": 11197
5618
+ "start": 11199
5627
5619
  },
5628
5620
  {
5629
5621
  "name": "validate_not_sqrt_hint_valid_test",
5630
- "start": 11329
5622
+ "start": 11331
5631
5623
  },
5632
5624
  {
5633
5625
  "name": "validate_not_sqrt_hint_zero_test",
5634
- "start": 11609
5626
+ "start": 11611
5635
5627
  },
5636
5628
  {
5637
5629
  "name": "validate_not_sqrt_hint_wrong_hint_test",
5638
- "start": 11826
5630
+ "start": 11828
5639
5631
  }
5640
5632
  ],
5641
5633
  "path": "/home/aztec-dev/aztec-packages/noir-projects/noir-protocol-circuits/crates/types/src/utils/field.nr",
5642
- "source": "pub fn field_from_bytes<let N: u32>(bytes: [u8; N], big_endian: bool) -> Field {\n assert(bytes.len() < 32, \"field_from_bytes: N must be less than 32\");\n let mut as_field = 0;\n let mut offset = 1;\n for i in 0..N {\n let mut index = i;\n if big_endian {\n index = N - i - 1;\n }\n as_field += (bytes[index] as Field) * offset;\n offset *= 256;\n }\n\n as_field\n}\n\n// Convert a 32 byte array to a field element by truncating the final byte\npub fn field_from_bytes_32_trunc(bytes32: [u8; 32]) -> Field {\n // Convert it to a field element\n let mut v = 1;\n let mut high = 0 as Field;\n let mut low = 0 as Field;\n\n for i in 0..15 {\n // covers bytes 16..30 (31 is truncated and ignored)\n low = low + (bytes32[15 + 15 - i] as Field) * v;\n v = v * 256;\n // covers bytes 0..14\n high = high + (bytes32[14 - i] as Field) * v;\n }\n // covers byte 15\n low = low + (bytes32[15] as Field) * v;\n\n low + high * v\n}\n\npub fn min(f1: Field, f2: Field) -> Field {\n if f1.lt(f2) {\n f1\n } else {\n f2\n }\n}\n\n// TODO: write doc-comments and tests for these magic constants.\n\nglobal KNOWN_NON_RESIDUE: Field = 5; // This is a non-residue in Noir's native Field.\nglobal C1: u32 = 28;\nglobal C3: Field = 40770029410420498293352137776570907027550720424234931066070132305055;\nglobal C5: Field = 19103219067921713944291392827692070036145651957329286315305642004821462161904;\n\n// @dev: only use this for _huge_ exponents y, when writing a constrained function.\n// If you're only exponentiating by a small value, first consider writing-out the multiplications by hand.\n// Only after you've measured the gates of that approach, consider using the native Field::pow_32 function.\n// Only if your exponent is larger than 32 bits, resort to using this function.\npub fn pow(x: Field, y: Field) -> Field {\n let mut r = 1 as Field;\n let b: [u1; 254] = y.to_le_bits();\n\n for i in 0..254 {\n r *= r;\n r *= (b[254 - 1 - i] as Field) * x + (1 - b[254 - 1 - i] as Field);\n }\n\n r\n}\n\n/// Returns Option::some(sqrt) if there is a square root, and Option::none() if there isn't.\npub fn sqrt(x: Field) -> Option<Field> {\n // Safety: if the hint returns the square root of x, then we simply square it\n // check the result equals x. If x is not square, we return a value that\n // enables us to prove that fact (see the `else` clause below).\n let (is_sq, maybe_sqrt) = unsafe { __sqrt(x) };\n\n if is_sq {\n let sqrt = maybe_sqrt;\n validate_sqrt_hint(x, sqrt);\n Option::some(sqrt)\n } else {\n let not_sqrt_hint = maybe_sqrt;\n validate_not_sqrt_hint(x, not_sqrt_hint);\n Option::none()\n }\n}\n\n// Boolean indicating whether Field element is a square, i.e. whether there exists a y in Field s.t. x = y*y.\nunconstrained fn is_square(x: Field) -> bool {\n let v = pow(x, -1 / 2);\n v * (v - 1) == 0\n}\n\n// Tonelli-Shanks algorithm for computing the square root of a Field element.\n// Requires C1 = max{c: 2^c divides (p-1)}, where p is the order of Field\n// as well as C3 = (C2 - 1)/2, where C2 = (p-1)/(2^c1),\n// and C5 = ZETA^C2, where ZETA is a non-square element of Field.\n// These are pre-computed above as globals.\nunconstrained fn tonelli_shanks_sqrt(x: Field) -> Field {\n let mut z = pow(x, C3);\n let mut t = z * z * x;\n z *= x;\n let mut b = t;\n let mut c = C5;\n\n for i in 0..(C1 - 1) {\n for _j in 1..(C1 - i - 1) {\n b *= b;\n }\n\n z *= if b == 1 { 1 } else { c };\n\n c *= c;\n\n t *= if b == 1 { 1 } else { c };\n\n b = t;\n }\n\n z\n}\n\n// NB: this doesn't return an option, because in the case of there _not_ being a square root, we still want to return a field element that allows us to then assert in the _constrained_ sqrt function that there is no sqrt.\nunconstrained fn __sqrt(x: Field) -> (bool, Field) {\n let is_sq = is_square(x);\n if is_sq {\n let sqrt = tonelli_shanks_sqrt(x);\n (true, sqrt)\n } else {\n // Demonstrate that x is not a square (a.k.a. a \"quadratic non-residue\").\n // Facts:\n // The Legendre symbol (\"LS\") of x, is x^((p-1)/2) (mod p).\n // - If x is a square, LS(x) = 1\n // - If x is not a square, LS(x) = -1\n // - If x = 0, LS(x) = 0.\n //\n // Hence:\n // sq * sq = sq // 1 * 1 = 1\n // non-sq * non-sq = sq // -1 * -1 = 1\n // sq * non-sq = non-sq // -1 * 1 = -1\n //\n // See: https://en.wikipedia.org/wiki/Legendre_symbol\n let demo_x_not_square = x * KNOWN_NON_RESIDUE;\n let not_sqrt = tonelli_shanks_sqrt(demo_x_not_square);\n (false, not_sqrt)\n }\n}\n\nfn validate_sqrt_hint(x: Field, hint: Field) {\n assert(hint * hint == x, f\"The claimed_sqrt {hint} is not the sqrt of x {x}\");\n}\n\nfn validate_not_sqrt_hint(x: Field, hint: Field) {\n // We need this assertion, because x = 0 would pass the other assertions in this\n // function, and we don't want people to be able to prove that 0 is not square!\n assert(x != 0, \"0 has a square root; you cannot claim it is not square\");\n // Demonstrate that x is not a square (a.k.a. a \"quadratic non-residue\").\n //\n // Facts:\n // The Legendre symbol (\"LS\") of x, is x^((p-1)/2) (mod p).\n // - If x is a square, LS(x) = 1\n // - If x is not a square, LS(x) = -1\n // - If x = 0, LS(x) = 0.\n //\n // Hence:\n // 1. sq * sq = sq // 1 * 1 = 1\n // 2. non-sq * non-sq = sq // -1 * -1 = 1\n // 3. sq * non-sq = non-sq // -1 * 1 = -1\n //\n // See: https://en.wikipedia.org/wiki/Legendre_symbol\n //\n // We want to demonstrate that this below multiplication falls under bullet-point (2):\n let demo_x_not_square = x * KNOWN_NON_RESIDUE;\n // I.e. we want to demonstrate that `demo_x_not_square` has Legendre symbol 1\n // (i.e. that it is a square), so we prove that it is square below.\n // Why do we want to prove that it has LS 1?\n // Well, since it was computed with a known-non-residue, its squareness implies we're\n // in case 2 (something multiplied by a known-non-residue yielding a result which\n // has a LS of 1), which implies that x must be a non-square. The unconstrained\n // function gave us the sqrt of demo_x_not_square, so all we need to do is\n // assert its squareness:\n assert(\n hint * hint == demo_x_not_square,\n f\"The hint {hint} does not demonstrate that {x} is not a square\",\n );\n}\n\n#[test]\nunconstrained fn bytes_field_test() {\n // Tests correctness of field_from_bytes_32_trunc against existing methods\n // Bytes representing 0x543e0a6642ffeb8039296861765a53407bba62bd1c97ca43374de950bbe0a7\n let inputs = [\n 84, 62, 10, 102, 66, 255, 235, 128, 57, 41, 104, 97, 118, 90, 83, 64, 123, 186, 98, 189, 28,\n 151, 202, 67, 55, 77, 233, 80, 187, 224, 167,\n ];\n let field = field_from_bytes(inputs, true);\n let return_bytes: [u8; 31] = field.to_be_bytes();\n assert_eq(inputs, return_bytes);\n // 32 bytes - we remove the final byte, and check it matches the field\n let inputs2 = [\n 84, 62, 10, 102, 66, 255, 235, 128, 57, 41, 104, 97, 118, 90, 83, 64, 123, 186, 98, 189, 28,\n 151, 202, 67, 55, 77, 233, 80, 187, 224, 167, 158,\n ];\n let field2 = field_from_bytes_32_trunc(inputs2);\n let return_bytes2: [u8; 31] = field2.to_be_bytes();\n\n assert_eq(return_bytes2, return_bytes);\n assert_eq(field2, field);\n}\n\n#[test]\nunconstrained fn max_field_test() {\n // Tests the hardcoded value in constants.nr vs underlying modulus\n // NB: We can't use 0-1 in constants.nr as it will be transpiled incorrectly to ts and sol constants files\n let max_value = crate::constants::MAX_FIELD_VALUE;\n assert_eq(max_value, 0 - 1);\n // modulus == 0 is tested elsewhere, so below is more of a sanity check\n let max_bytes: [u8; 32] = max_value.to_be_bytes();\n let mod_bytes = std::field::modulus_be_bytes();\n for i in 0..31 {\n assert_eq(max_bytes[i], mod_bytes[i]);\n }\n assert_eq(max_bytes[31], mod_bytes[31] - 1);\n}\n\n#[test]\nunconstrained fn sqrt_valid_test() {\n let x = 16; // examples: 16, 9, 25, 81\n let result = sqrt(x);\n assert(result.is_some());\n assert_eq(result.unwrap() * result.unwrap(), x);\n}\n\n#[test]\nunconstrained fn sqrt_invalid_test() {\n let x = KNOWN_NON_RESIDUE; // has no square root in the field\n let result = sqrt(x);\n assert(result.is_none());\n}\n\n#[test]\nunconstrained fn sqrt_zero_test() {\n let result = sqrt(0);\n assert(result.is_some());\n assert_eq(result.unwrap(), 0);\n}\n\n#[test]\nunconstrained fn sqrt_one_test() {\n let result = sqrt(1);\n assert(result.is_some());\n assert_eq(result.unwrap() * result.unwrap(), 1);\n}\n\n#[test]\nunconstrained fn field_from_bytes_empty_test() {\n let empty: [u8; 0] = [];\n let result = field_from_bytes(empty, true);\n assert_eq(result, 0);\n\n let result_le = field_from_bytes(empty, false);\n assert_eq(result_le, 0);\n}\n\n#[test]\nunconstrained fn field_from_bytes_little_endian_test() {\n // Test little-endian conversion: [0x01, 0x02] should be 0x0201 = 513\n let bytes = [0x01, 0x02];\n let result_le = field_from_bytes(bytes, false);\n assert_eq(result_le, 0x0201);\n\n // Compare with big-endian: [0x01, 0x02] should be 0x0102 = 258\n let result_be = field_from_bytes(bytes, true);\n assert_eq(result_be, 0x0102);\n}\n\n#[test]\nunconstrained fn pow_test() {\n assert_eq(pow(2, 0), 1);\n assert_eq(pow(2, 1), 2);\n assert_eq(pow(2, 10), 1024);\n assert_eq(pow(3, 5), 243);\n assert_eq(pow(0, 5), 0);\n assert_eq(pow(1, 100), 1);\n}\n\n#[test]\nunconstrained fn min_test() {\n assert_eq(min(5, 10), 5);\n assert_eq(min(10, 5), 5);\n assert_eq(min(7, 7), 7);\n assert_eq(min(0, 1), 0);\n}\n\n#[test]\nunconstrained fn sqrt_has_two_roots_test() {\n // Every square has two roots: r and -r (i.e., p - r)\n // sqrt(16) can return 4 or -4\n let x = 16;\n let result = sqrt(x).unwrap();\n assert(result * result == x);\n // The other root is -result\n let other_root = 0 - result;\n assert(other_root * other_root == x);\n // Verify they are different (unless x = 0)\n assert(result != other_root);\n\n // Same for 9: roots are 3 and -3\n let y = 9;\n let result_y = sqrt(y).unwrap();\n assert(result_y * result_y == y);\n let other_root_y = 0 - result_y;\n assert(other_root_y * other_root_y == y);\n assert(result_y != other_root_y);\n}\n\n#[test]\nunconstrained fn sqrt_negative_one_test() {\n let x = 0 - 1;\n let result = sqrt(x);\n assert(result.unwrap() == 0x30644e72e131a029048b6e193fd841045cea24f6fd736bec231204708f703636);\n}\n\n#[test]\nunconstrained fn validate_sqrt_hint_valid_test() {\n // 4 is a valid sqrt of 16\n validate_sqrt_hint(16, 4);\n // -4 is also a valid sqrt of 16\n validate_sqrt_hint(16, 0 - 4);\n // 0 is a valid sqrt of 0\n validate_sqrt_hint(0, 0);\n // 1 is a valid sqrt of 1\n validate_sqrt_hint(1, 1);\n // -1 is also a valid sqrt of 1\n validate_sqrt_hint(1, 0 - 1);\n}\n\n#[test(should_fail_with = \"is not the sqrt of x\")]\nunconstrained fn validate_sqrt_hint_invalid_test() {\n // 5 is not a valid sqrt of 16\n validate_sqrt_hint(16, 5);\n}\n\n#[test]\nunconstrained fn validate_not_sqrt_hint_valid_test() {\n // 5 (KNOWN_NON_RESIDUE) is not a square.\n let x = KNOWN_NON_RESIDUE;\n let hint = tonelli_shanks_sqrt(x * KNOWN_NON_RESIDUE);\n validate_not_sqrt_hint(x, hint);\n}\n\n#[test(should_fail_with = \"0 has a square root\")]\nunconstrained fn validate_not_sqrt_hint_zero_test() {\n // 0 has a square root, so we cannot claim it is not square\n validate_not_sqrt_hint(0, 0);\n}\n\n#[test(should_fail_with = \"does not demonstrate that\")]\nunconstrained fn validate_not_sqrt_hint_wrong_hint_test() {\n // Provide a wrong hint for a non-square\n let x = KNOWN_NON_RESIDUE;\n validate_not_sqrt_hint(x, 123);\n}\n"
5634
+ "source": "pub fn field_from_bytes<let N: u32>(bytes: [u8; N], big_endian: bool) -> Field {\n assert(bytes.len() < 32, \"field_from_bytes: N must be less than 32\");\n let mut as_field = 0;\n let mut offset = 1;\n for i in 0..N {\n let mut index = i;\n if big_endian {\n index = N - i - 1;\n }\n as_field += (bytes[index] as Field) * offset;\n offset *= 256;\n }\n\n as_field\n}\n\n// Convert a 32 byte array to a field element by truncating the final byte\npub fn field_from_bytes_32_trunc(bytes32: [u8; 32]) -> Field {\n // Convert it to a field element\n let mut v = 1;\n let mut high = 0 as Field;\n let mut low = 0 as Field;\n\n for i in 0..15 {\n // covers bytes 16..30 (31 is truncated and ignored)\n low = low + (bytes32[15 + 15 - i] as Field) * v;\n v = v * 256;\n // covers bytes 0..14\n high = high + (bytes32[14 - i] as Field) * v;\n }\n // covers byte 15\n low = low + (bytes32[15] as Field) * v;\n\n low + high * v\n}\n\npub fn min(f1: Field, f2: Field) -> Field {\n if f1.lt(f2) {\n f1\n } else {\n f2\n }\n}\n\n// TODO: write doc-comments and tests for these magic constants.\n\nglobal KNOWN_NON_RESIDUE: Field = 5; // This is a non-residue in Noir's native Field.\nglobal C1: u32 = 28;\nglobal C3: Field = 40770029410420498293352137776570907027550720424234931066070132305055;\nglobal C5: Field = 19103219067921713944291392827692070036145651957329286315305642004821462161904;\n\n// @dev: only use this for _huge_ exponents y, when writing a constrained function.\n// If you're only exponentiating by a small value, first consider writing-out the multiplications by hand.\n// Only after you've measured the gates of that approach, consider using the native Field::pow_32 function.\n// Only if your exponent is larger than 32 bits, resort to using this function.\npub fn pow(x: Field, y: Field) -> Field {\n let mut r = 1 as Field;\n let b: [bool; 254] = y.to_le_bits();\n\n for i in 0..254 {\n r *= r;\n r *= (b[254 - 1 - i] as Field) * x + (1 - b[254 - 1 - i] as Field);\n }\n\n r\n}\n\n/// Returns Option::some(sqrt) if there is a square root, and Option::none() if there isn't.\npub fn sqrt(x: Field) -> Option<Field> {\n // Safety: if the hint returns the square root of x, then we simply square it\n // check the result equals x. If x is not square, we return a value that\n // enables us to prove that fact (see the `else` clause below).\n let (is_sq, maybe_sqrt) = unsafe { __sqrt(x) };\n\n if is_sq {\n let sqrt = maybe_sqrt;\n validate_sqrt_hint(x, sqrt);\n Option::some(sqrt)\n } else {\n let not_sqrt_hint = maybe_sqrt;\n validate_not_sqrt_hint(x, not_sqrt_hint);\n Option::none()\n }\n}\n\n// Boolean indicating whether Field element is a square, i.e. whether there exists a y in Field s.t. x = y*y.\nunconstrained fn is_square(x: Field) -> bool {\n let v = pow(x, -1 / 2);\n v * (v - 1) == 0\n}\n\n// Tonelli-Shanks algorithm for computing the square root of a Field element.\n// Requires C1 = max{c: 2^c divides (p-1)}, where p is the order of Field\n// as well as C3 = (C2 - 1)/2, where C2 = (p-1)/(2^c1),\n// and C5 = ZETA^C2, where ZETA is a non-square element of Field.\n// These are pre-computed above as globals.\nunconstrained fn tonelli_shanks_sqrt(x: Field) -> Field {\n let mut z = pow(x, C3);\n let mut t = z * z * x;\n z *= x;\n let mut b = t;\n let mut c = C5;\n\n for i in 0..(C1 - 1) {\n for _j in 1..(C1 - i - 1) {\n b *= b;\n }\n\n z *= if b == 1 { 1 } else { c };\n\n c *= c;\n\n t *= if b == 1 { 1 } else { c };\n\n b = t;\n }\n\n z\n}\n\n// NB: this doesn't return an option, because in the case of there _not_ being a square root, we still want to return a field element that allows us to then assert in the _constrained_ sqrt function that there is no sqrt.\nunconstrained fn __sqrt(x: Field) -> (bool, Field) {\n let is_sq = is_square(x);\n if is_sq {\n let sqrt = tonelli_shanks_sqrt(x);\n (true, sqrt)\n } else {\n // Demonstrate that x is not a square (a.k.a. a \"quadratic non-residue\").\n // Facts:\n // The Legendre symbol (\"LS\") of x, is x^((p-1)/2) (mod p).\n // - If x is a square, LS(x) = 1\n // - If x is not a square, LS(x) = -1\n // - If x = 0, LS(x) = 0.\n //\n // Hence:\n // sq * sq = sq // 1 * 1 = 1\n // non-sq * non-sq = sq // -1 * -1 = 1\n // sq * non-sq = non-sq // -1 * 1 = -1\n //\n // See: https://en.wikipedia.org/wiki/Legendre_symbol\n let demo_x_not_square = x * KNOWN_NON_RESIDUE;\n let not_sqrt = tonelli_shanks_sqrt(demo_x_not_square);\n (false, not_sqrt)\n }\n}\n\nfn validate_sqrt_hint(x: Field, hint: Field) {\n assert(hint * hint == x, f\"The claimed_sqrt {hint} is not the sqrt of x {x}\");\n}\n\nfn validate_not_sqrt_hint(x: Field, hint: Field) {\n // We need this assertion, because x = 0 would pass the other assertions in this\n // function, and we don't want people to be able to prove that 0 is not square!\n assert(x != 0, \"0 has a square root; you cannot claim it is not square\");\n // Demonstrate that x is not a square (a.k.a. a \"quadratic non-residue\").\n //\n // Facts:\n // The Legendre symbol (\"LS\") of x, is x^((p-1)/2) (mod p).\n // - If x is a square, LS(x) = 1\n // - If x is not a square, LS(x) = -1\n // - If x = 0, LS(x) = 0.\n //\n // Hence:\n // 1. sq * sq = sq // 1 * 1 = 1\n // 2. non-sq * non-sq = sq // -1 * -1 = 1\n // 3. sq * non-sq = non-sq // -1 * 1 = -1\n //\n // See: https://en.wikipedia.org/wiki/Legendre_symbol\n //\n // We want to demonstrate that this below multiplication falls under bullet-point (2):\n let demo_x_not_square = x * KNOWN_NON_RESIDUE;\n // I.e. we want to demonstrate that `demo_x_not_square` has Legendre symbol 1\n // (i.e. that it is a square), so we prove that it is square below.\n // Why do we want to prove that it has LS 1?\n // Well, since it was computed with a known-non-residue, its squareness implies we're\n // in case 2 (something multiplied by a known-non-residue yielding a result which\n // has a LS of 1), which implies that x must be a non-square. The unconstrained\n // function gave us the sqrt of demo_x_not_square, so all we need to do is\n // assert its squareness:\n assert(\n hint * hint == demo_x_not_square,\n f\"The hint {hint} does not demonstrate that {x} is not a square\",\n );\n}\n\n#[test]\nunconstrained fn bytes_field_test() {\n // Tests correctness of field_from_bytes_32_trunc against existing methods\n // Bytes representing 0x543e0a6642ffeb8039296861765a53407bba62bd1c97ca43374de950bbe0a7\n let inputs = [\n 84, 62, 10, 102, 66, 255, 235, 128, 57, 41, 104, 97, 118, 90, 83, 64, 123, 186, 98, 189, 28,\n 151, 202, 67, 55, 77, 233, 80, 187, 224, 167,\n ];\n let field = field_from_bytes(inputs, true);\n let return_bytes: [u8; 31] = field.to_be_bytes();\n assert_eq(inputs, return_bytes);\n // 32 bytes - we remove the final byte, and check it matches the field\n let inputs2 = [\n 84, 62, 10, 102, 66, 255, 235, 128, 57, 41, 104, 97, 118, 90, 83, 64, 123, 186, 98, 189, 28,\n 151, 202, 67, 55, 77, 233, 80, 187, 224, 167, 158,\n ];\n let field2 = field_from_bytes_32_trunc(inputs2);\n let return_bytes2: [u8; 31] = field2.to_be_bytes();\n\n assert_eq(return_bytes2, return_bytes);\n assert_eq(field2, field);\n}\n\n#[test]\nunconstrained fn max_field_test() {\n // Tests the hardcoded value in constants.nr vs underlying modulus\n // NB: We can't use 0-1 in constants.nr as it will be transpiled incorrectly to ts and sol constants files\n let max_value = crate::constants::MAX_FIELD_VALUE;\n assert_eq(max_value, 0 - 1);\n // modulus == 0 is tested elsewhere, so below is more of a sanity check\n let max_bytes: [u8; 32] = max_value.to_be_bytes();\n let mod_bytes = std::field::modulus_be_bytes();\n for i in 0..31 {\n assert_eq(max_bytes[i], mod_bytes[i]);\n }\n assert_eq(max_bytes[31], mod_bytes[31] - 1);\n}\n\n#[test]\nunconstrained fn sqrt_valid_test() {\n let x = 16; // examples: 16, 9, 25, 81\n let result = sqrt(x);\n assert(result.is_some());\n assert_eq(result.unwrap() * result.unwrap(), x);\n}\n\n#[test]\nunconstrained fn sqrt_invalid_test() {\n let x = KNOWN_NON_RESIDUE; // has no square root in the field\n let result = sqrt(x);\n assert(result.is_none());\n}\n\n#[test]\nunconstrained fn sqrt_zero_test() {\n let result = sqrt(0);\n assert(result.is_some());\n assert_eq(result.unwrap(), 0);\n}\n\n#[test]\nunconstrained fn sqrt_one_test() {\n let result = sqrt(1);\n assert(result.is_some());\n assert_eq(result.unwrap() * result.unwrap(), 1);\n}\n\n#[test]\nunconstrained fn field_from_bytes_empty_test() {\n let empty: [u8; 0] = [];\n let result = field_from_bytes(empty, true);\n assert_eq(result, 0);\n\n let result_le = field_from_bytes(empty, false);\n assert_eq(result_le, 0);\n}\n\n#[test]\nunconstrained fn field_from_bytes_little_endian_test() {\n // Test little-endian conversion: [0x01, 0x02] should be 0x0201 = 513\n let bytes = [0x01, 0x02];\n let result_le = field_from_bytes(bytes, false);\n assert_eq(result_le, 0x0201);\n\n // Compare with big-endian: [0x01, 0x02] should be 0x0102 = 258\n let result_be = field_from_bytes(bytes, true);\n assert_eq(result_be, 0x0102);\n}\n\n#[test]\nunconstrained fn pow_test() {\n assert_eq(pow(2, 0), 1);\n assert_eq(pow(2, 1), 2);\n assert_eq(pow(2, 10), 1024);\n assert_eq(pow(3, 5), 243);\n assert_eq(pow(0, 5), 0);\n assert_eq(pow(1, 100), 1);\n}\n\n#[test]\nunconstrained fn min_test() {\n assert_eq(min(5, 10), 5);\n assert_eq(min(10, 5), 5);\n assert_eq(min(7, 7), 7);\n assert_eq(min(0, 1), 0);\n}\n\n#[test]\nunconstrained fn sqrt_has_two_roots_test() {\n // Every square has two roots: r and -r (i.e., p - r)\n // sqrt(16) can return 4 or -4\n let x = 16;\n let result = sqrt(x).unwrap();\n assert(result * result == x);\n // The other root is -result\n let other_root = 0 - result;\n assert(other_root * other_root == x);\n // Verify they are different (unless x = 0)\n assert(result != other_root);\n\n // Same for 9: roots are 3 and -3\n let y = 9;\n let result_y = sqrt(y).unwrap();\n assert(result_y * result_y == y);\n let other_root_y = 0 - result_y;\n assert(other_root_y * other_root_y == y);\n assert(result_y != other_root_y);\n}\n\n#[test]\nunconstrained fn sqrt_negative_one_test() {\n let x = 0 - 1;\n let result = sqrt(x);\n assert(result.unwrap() == 0x30644e72e131a029048b6e193fd841045cea24f6fd736bec231204708f703636);\n}\n\n#[test]\nunconstrained fn validate_sqrt_hint_valid_test() {\n // 4 is a valid sqrt of 16\n validate_sqrt_hint(16, 4);\n // -4 is also a valid sqrt of 16\n validate_sqrt_hint(16, 0 - 4);\n // 0 is a valid sqrt of 0\n validate_sqrt_hint(0, 0);\n // 1 is a valid sqrt of 1\n validate_sqrt_hint(1, 1);\n // -1 is also a valid sqrt of 1\n validate_sqrt_hint(1, 0 - 1);\n}\n\n#[test(should_fail_with = \"is not the sqrt of x\")]\nunconstrained fn validate_sqrt_hint_invalid_test() {\n // 5 is not a valid sqrt of 16\n validate_sqrt_hint(16, 5);\n}\n\n#[test]\nunconstrained fn validate_not_sqrt_hint_valid_test() {\n // 5 (KNOWN_NON_RESIDUE) is not a square.\n let x = KNOWN_NON_RESIDUE;\n let hint = tonelli_shanks_sqrt(x * KNOWN_NON_RESIDUE);\n validate_not_sqrt_hint(x, hint);\n}\n\n#[test(should_fail_with = \"0 has a square root\")]\nunconstrained fn validate_not_sqrt_hint_zero_test() {\n // 0 has a square root, so we cannot claim it is not square\n validate_not_sqrt_hint(0, 0);\n}\n\n#[test(should_fail_with = \"does not demonstrate that\")]\nunconstrained fn validate_not_sqrt_hint_wrong_hint_test() {\n // Provide a wrong hint for a non-square\n let x = KNOWN_NON_RESIDUE;\n validate_not_sqrt_hint(x, 123);\n}\n"
5643
5635
  },
5644
5636
  "409": {
5645
5637
  "function_locations": [
@@ -5819,331 +5811,315 @@
5819
5811
  "function_locations": [
5820
5812
  {
5821
5813
  "name": "<impl Serialize for bool>::serialize",
5822
- "start": 728
5814
+ "start": 693
5823
5815
  },
5824
5816
  {
5825
5817
  "name": "<impl Serialize for bool>::stream_serialize",
5826
- "start": 949
5818
+ "start": 914
5827
5819
  },
5828
5820
  {
5829
5821
  "name": "<impl Deserialize for bool>::deserialize",
5830
- "start": 1117
5822
+ "start": 1082
5831
5823
  },
5832
5824
  {
5833
5825
  "name": "<impl Deserialize for bool>::stream_deserialize",
5834
- "start": 1363
5835
- },
5836
- {
5837
- "name": "<impl Serialize for u1>::serialize",
5838
- "start": 1505
5839
- },
5840
- {
5841
- "name": "<impl Serialize for u1>::stream_serialize",
5842
- "start": 1726
5843
- },
5844
- {
5845
- "name": "<impl Deserialize for u1>::deserialize",
5846
- "start": 1890
5847
- },
5848
- {
5849
- "name": "<impl Deserialize for u1>::stream_deserialize",
5850
- "start": 2136
5826
+ "start": 1328
5851
5827
  },
5852
5828
  {
5853
5829
  "name": "<impl Serialize for u8>::serialize",
5854
- "start": 2279
5830
+ "start": 1470
5855
5831
  },
5856
5832
  {
5857
5833
  "name": "<impl Serialize for u8>::stream_serialize",
5858
- "start": 2500
5834
+ "start": 1691
5859
5835
  },
5860
5836
  {
5861
5837
  "name": "<impl Deserialize for u8>::deserialize",
5862
- "start": 2664
5838
+ "start": 1855
5863
5839
  },
5864
5840
  {
5865
5841
  "name": "<impl Deserialize for u8>::stream_deserialize",
5866
- "start": 2910
5842
+ "start": 2101
5867
5843
  },
5868
5844
  {
5869
5845
  "name": "<impl Serialize for u16>::serialize",
5870
- "start": 3055
5846
+ "start": 2246
5871
5847
  },
5872
5848
  {
5873
5849
  "name": "<impl Serialize for u16>::stream_serialize",
5874
- "start": 3276
5850
+ "start": 2467
5875
5851
  },
5876
5852
  {
5877
5853
  "name": "<impl Deserialize for u16>::deserialize",
5878
- "start": 3442
5854
+ "start": 2633
5879
5855
  },
5880
5856
  {
5881
5857
  "name": "<impl Deserialize for u16>::stream_deserialize",
5882
- "start": 3688
5858
+ "start": 2879
5883
5859
  },
5884
5860
  {
5885
5861
  "name": "<impl Serialize for u32>::serialize",
5886
- "start": 3834
5862
+ "start": 3025
5887
5863
  },
5888
5864
  {
5889
5865
  "name": "<impl Serialize for u32>::stream_serialize",
5890
- "start": 4055
5866
+ "start": 3246
5891
5867
  },
5892
5868
  {
5893
5869
  "name": "<impl Deserialize for u32>::deserialize",
5894
- "start": 4221
5870
+ "start": 3412
5895
5871
  },
5896
5872
  {
5897
5873
  "name": "<impl Deserialize for u32>::stream_deserialize",
5898
- "start": 4467
5874
+ "start": 3658
5899
5875
  },
5900
5876
  {
5901
5877
  "name": "<impl Serialize for u64>::serialize",
5902
- "start": 4613
5878
+ "start": 3804
5903
5879
  },
5904
5880
  {
5905
5881
  "name": "<impl Serialize for u64>::stream_serialize",
5906
- "start": 4834
5882
+ "start": 4025
5907
5883
  },
5908
5884
  {
5909
5885
  "name": "<impl Deserialize for u64>::deserialize",
5910
- "start": 5000
5886
+ "start": 4191
5911
5887
  },
5912
5888
  {
5913
5889
  "name": "<impl Deserialize for u64>::stream_deserialize",
5914
- "start": 5246
5890
+ "start": 4437
5915
5891
  },
5916
5892
  {
5917
5893
  "name": "<impl Serialize for u128>::serialize",
5918
- "start": 5394
5894
+ "start": 4585
5919
5895
  },
5920
5896
  {
5921
5897
  "name": "<impl Serialize for u128>::stream_serialize",
5922
- "start": 5615
5898
+ "start": 4806
5923
5899
  },
5924
5900
  {
5925
5901
  "name": "<impl Deserialize for u128>::deserialize",
5926
- "start": 5783
5902
+ "start": 4974
5927
5903
  },
5928
5904
  {
5929
5905
  "name": "<impl Deserialize for u128>::stream_deserialize",
5930
- "start": 6029
5906
+ "start": 5220
5931
5907
  },
5932
5908
  {
5933
5909
  "name": "<impl Serialize for Field>::serialize",
5934
- "start": 6180
5910
+ "start": 5371
5935
5911
  },
5936
5912
  {
5937
5913
  "name": "<impl Serialize for Field>::stream_serialize",
5938
- "start": 6401
5914
+ "start": 5592
5939
5915
  },
5940
5916
  {
5941
5917
  "name": "<impl Deserialize for Field>::deserialize",
5942
- "start": 6562
5918
+ "start": 5753
5943
5919
  },
5944
5920
  {
5945
5921
  "name": "<impl Deserialize for Field>::stream_deserialize",
5946
- "start": 6808
5922
+ "start": 5999
5947
5923
  },
5948
5924
  {
5949
5925
  "name": "<impl Serialize for i8>::serialize",
5950
- "start": 6945
5926
+ "start": 6136
5951
5927
  },
5952
5928
  {
5953
5929
  "name": "<impl Serialize for i8>::stream_serialize",
5954
- "start": 7166
5930
+ "start": 6357
5955
5931
  },
5956
5932
  {
5957
5933
  "name": "<impl Deserialize for i8>::deserialize",
5958
- "start": 7336
5934
+ "start": 6527
5959
5935
  },
5960
5936
  {
5961
5937
  "name": "<impl Deserialize for i8>::stream_deserialize",
5962
- "start": 7582
5938
+ "start": 6773
5963
5939
  },
5964
5940
  {
5965
5941
  "name": "<impl Serialize for i16>::serialize",
5966
- "start": 7733
5942
+ "start": 6924
5967
5943
  },
5968
5944
  {
5969
5945
  "name": "<impl Serialize for i16>::stream_serialize",
5970
- "start": 7954
5946
+ "start": 7145
5971
5947
  },
5972
5948
  {
5973
5949
  "name": "<impl Deserialize for i16>::deserialize",
5974
- "start": 8127
5950
+ "start": 7318
5975
5951
  },
5976
5952
  {
5977
5953
  "name": "<impl Deserialize for i16>::stream_deserialize",
5978
- "start": 8373
5954
+ "start": 7564
5979
5955
  },
5980
5956
  {
5981
5957
  "name": "<impl Serialize for i32>::serialize",
5982
- "start": 8526
5958
+ "start": 7717
5983
5959
  },
5984
5960
  {
5985
5961
  "name": "<impl Serialize for i32>::stream_serialize",
5986
- "start": 8747
5962
+ "start": 7938
5987
5963
  },
5988
5964
  {
5989
5965
  "name": "<impl Deserialize for i32>::deserialize",
5990
- "start": 8920
5966
+ "start": 8111
5991
5967
  },
5992
5968
  {
5993
5969
  "name": "<impl Deserialize for i32>::stream_deserialize",
5994
- "start": 9166
5970
+ "start": 8357
5995
5971
  },
5996
5972
  {
5997
5973
  "name": "<impl Serialize for i64>::serialize",
5998
- "start": 9319
5974
+ "start": 8510
5999
5975
  },
6000
5976
  {
6001
5977
  "name": "<impl Serialize for i64>::stream_serialize",
6002
- "start": 9540
5978
+ "start": 8731
6003
5979
  },
6004
5980
  {
6005
5981
  "name": "<impl Deserialize for i64>::deserialize",
6006
- "start": 9713
5982
+ "start": 8904
6007
5983
  },
6008
5984
  {
6009
5985
  "name": "<impl Deserialize for i64>::stream_deserialize",
6010
- "start": 9959
5986
+ "start": 9150
6011
5987
  },
6012
5988
  {
6013
5989
  "name": "<impl Serialize for [T; M]>::serialize",
6014
- "start": 10159
5990
+ "start": 9350
6015
5991
  },
6016
5992
  {
6017
5993
  "name": "<impl Serialize for [T; M]>::stream_serialize",
6018
- "start": 10380
5994
+ "start": 9571
6019
5995
  },
6020
5996
  {
6021
5997
  "name": "<impl Deserialize for [T; M]>::deserialize",
6022
- "start": 10640
5998
+ "start": 9831
6023
5999
  },
6024
6000
  {
6025
6001
  "name": "<impl Deserialize for [T; M]>::stream_deserialize",
6026
- "start": 10886
6002
+ "start": 10077
6027
6003
  },
6028
6004
  {
6029
6005
  "name": "<impl Serialize for Option<T>>::serialize",
6030
- "start": 11198
6006
+ "start": 10389
6031
6007
  },
6032
6008
  {
6033
6009
  "name": "<impl Serialize for Option<T>>::stream_serialize",
6034
- "start": 11419
6010
+ "start": 10610
6035
6011
  },
6036
6012
  {
6037
6013
  "name": "<impl Deserialize for Option<T>>::deserialize",
6038
- "start": 11806
6014
+ "start": 10997
6039
6015
  },
6040
6016
  {
6041
6017
  "name": "<impl Deserialize for Option<T>>::stream_deserialize",
6042
- "start": 12052
6018
+ "start": 11243
6043
6019
  },
6044
6020
  {
6045
6021
  "name": "<impl Serialize for EmbeddedCurveScalar>::serialize",
6046
- "start": 12430
6022
+ "start": 11621
6047
6023
  },
6048
6024
  {
6049
6025
  "name": "<impl Serialize for EmbeddedCurveScalar>::stream_serialize",
6050
- "start": 12553
6026
+ "start": 11744
6051
6027
  },
6052
6028
  {
6053
6029
  "name": "<impl Deserialize for EmbeddedCurveScalar>::deserialize",
6054
- "start": 12753
6030
+ "start": 11944
6055
6031
  },
6056
6032
  {
6057
6033
  "name": "<impl Deserialize for EmbeddedCurveScalar>::stream_deserialize",
6058
- "start": 12899
6034
+ "start": 12090
6059
6035
  },
6060
6036
  {
6061
6037
  "name": "<impl Serialize for EmbeddedCurvePoint>::serialize",
6062
- "start": 13106
6038
+ "start": 12297
6063
6039
  },
6064
6040
  {
6065
6041
  "name": "<impl Serialize for EmbeddedCurvePoint>::stream_serialize",
6066
- "start": 13233
6042
+ "start": 12397
6067
6043
  },
6068
6044
  {
6069
6045
  "name": "<impl Deserialize for EmbeddedCurvePoint>::deserialize",
6070
- "start": 13478
6046
+ "start": 12593
6071
6047
  },
6072
6048
  {
6073
6049
  "name": "<impl Deserialize for EmbeddedCurvePoint>::stream_deserialize",
6074
- "start": 13651
6050
+ "start": 12737
6075
6051
  },
6076
6052
  {
6077
6053
  "name": "<impl Deserialize for str<M>>::deserialize",
6078
- "start": 13863
6054
+ "start": 12916
6079
6055
  },
6080
6056
  {
6081
6057
  "name": "<impl Deserialize for str<M>>::stream_deserialize",
6082
- "start": 14109
6058
+ "start": 13162
6083
6059
  },
6084
6060
  {
6085
6061
  "name": "<impl Serialize for str<M>>::serialize",
6086
- "start": 14342
6062
+ "start": 13395
6087
6063
  },
6088
6064
  {
6089
6065
  "name": "<impl Serialize for str<M>>::stream_serialize",
6090
- "start": 14563
6066
+ "start": 13616
6091
6067
  },
6092
6068
  {
6093
6069
  "name": "<impl Deserialize for BoundedVec<T, M>>::deserialize",
6094
- "start": 14944
6070
+ "start": 13997
6095
6071
  },
6096
6072
  {
6097
6073
  "name": "<impl Deserialize for BoundedVec<T, M>>::stream_deserialize",
6098
- "start": 15190
6074
+ "start": 14243
6099
6075
  },
6100
6076
  {
6101
6077
  "name": "<impl Deserialize for ()>::deserialize",
6102
- "start": 16246
6078
+ "start": 15299
6103
6079
  },
6104
6080
  {
6105
6081
  "name": "<impl Deserialize for ()>::stream_deserialize",
6106
- "start": 16493
6082
+ "start": 15546
6107
6083
  },
6108
6084
  {
6109
6085
  "name": "<impl Serialize for BoundedVec<T, M>>::serialize",
6110
- "start": 16858
6086
+ "start": 15911
6111
6087
  },
6112
6088
  {
6113
6089
  "name": "<impl Serialize for BoundedVec<T, M>>::stream_serialize",
6114
- "start": 17079
6090
+ "start": 16132
6115
6091
  },
6116
6092
  {
6117
6093
  "name": "make_slice",
6118
- "start": 17564
6094
+ "start": 16617
6119
6095
  },
6120
6096
  {
6121
6097
  "name": "impl_serialize_for_tuple",
6122
- "start": 17814
6098
+ "start": 16867
6123
6099
  },
6124
6100
  {
6125
6101
  "name": "<impl Serialize for (T1,)>::serialize",
6126
- "start": 21105
6102
+ "start": 20158
6127
6103
  },
6128
6104
  {
6129
6105
  "name": "<impl Serialize for (T1,)>::stream_serialize",
6130
- "start": 21356
6106
+ "start": 20409
6131
6107
  },
6132
6108
  {
6133
6109
  "name": "<impl Deserialize for (T1,)>::deserialize",
6134
- "start": 21563
6110
+ "start": 20616
6135
6111
  },
6136
6112
  {
6137
6113
  "name": "<impl Deserialize for (T1,)>::stream_deserialize",
6138
- "start": 21824
6114
+ "start": 20877
6139
6115
  },
6140
6116
  {
6141
6117
  "name": "bounded_vec_serialization",
6142
- "start": 22173
6118
+ "start": 21226
6143
6119
  }
6144
6120
  ],
6145
6121
  "path": "/home/aztec-dev/aztec-packages/noir-projects/noir-protocol-circuits/crates/serde/src/type_impls.nr",
6146
- "source": "use crate::{reader::Reader, serialization::{Deserialize, Serialize}, writer::Writer};\nuse std::embedded_curve_ops::EmbeddedCurvePoint;\nuse std::embedded_curve_ops::EmbeddedCurveScalar;\n\nglobal U1_SERIALIZED_LEN: u32 = 1;\nglobal BOOL_SERIALIZED_LEN: u32 = 1;\nglobal U8_SERIALIZED_LEN: u32 = 1;\nglobal U16_SERIALIZED_LEN: u32 = 1;\nglobal U32_SERIALIZED_LEN: u32 = 1;\nglobal U64_SERIALIZED_LEN: u32 = 1;\nglobal U128_SERIALIZED_LEN: u32 = 1;\nglobal FIELD_SERIALIZED_LEN: u32 = 1;\nglobal I8_SERIALIZED_LEN: u32 = 1;\nglobal I16_SERIALIZED_LEN: u32 = 1;\nglobal I32_SERIALIZED_LEN: u32 = 1;\nglobal I64_SERIALIZED_LEN: u32 = 1;\n\nimpl Serialize for bool {\n let N: u32 = BOOL_SERIALIZED_LEN;\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: Writer<Self::N> = Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize<let K: u32>(self, writer: &mut Writer<K>) {\n writer.write(self as Field);\n }\n}\n\nimpl Deserialize for bool {\n let N: u32 = BOOL_SERIALIZED_LEN;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize<let K: u32>(reader: &mut Reader<K>) -> bool {\n reader.read() != 0\n }\n}\n\nimpl Serialize for u1 {\n let N: u32 = U1_SERIALIZED_LEN;\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: Writer<Self::N> = Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize<let K: u32>(self, writer: &mut Writer<K>) {\n writer.write(self as Field);\n }\n}\n\nimpl Deserialize for u1 {\n let N: u32 = U1_SERIALIZED_LEN;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize<let K: u32>(reader: &mut Reader<K>) -> Self {\n reader.read() as u1\n }\n}\n\nimpl Serialize for u8 {\n let N: u32 = U8_SERIALIZED_LEN;\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: Writer<Self::N> = Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize<let K: u32>(self, writer: &mut Writer<K>) {\n writer.write(self as Field);\n }\n}\n\nimpl Deserialize for u8 {\n let N: u32 = U8_SERIALIZED_LEN;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize<let K: u32>(reader: &mut Reader<K>) -> Self {\n reader.read() as u8\n }\n}\n\nimpl Serialize for u16 {\n let N: u32 = U16_SERIALIZED_LEN;\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: Writer<Self::N> = Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize<let K: u32>(self, writer: &mut Writer<K>) {\n writer.write(self as Field);\n }\n}\n\nimpl Deserialize for u16 {\n let N: u32 = U16_SERIALIZED_LEN;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize<let K: u32>(reader: &mut Reader<K>) -> Self {\n reader.read() as u16\n }\n}\n\nimpl Serialize for u32 {\n let N: u32 = U32_SERIALIZED_LEN;\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: Writer<Self::N> = Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize<let K: u32>(self, writer: &mut Writer<K>) {\n writer.write(self as Field);\n }\n}\n\nimpl Deserialize for u32 {\n let N: u32 = U32_SERIALIZED_LEN;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize<let K: u32>(reader: &mut Reader<K>) -> Self {\n reader.read() as u32\n }\n}\n\nimpl Serialize for u64 {\n let N: u32 = U64_SERIALIZED_LEN;\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: Writer<Self::N> = Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize<let K: u32>(self, writer: &mut Writer<K>) {\n writer.write(self as Field);\n }\n}\n\nimpl Deserialize for u64 {\n let N: u32 = U64_SERIALIZED_LEN;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize<let K: u32>(reader: &mut Reader<K>) -> Self {\n reader.read() as u64\n }\n}\n\nimpl Serialize for u128 {\n let N: u32 = U128_SERIALIZED_LEN;\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: Writer<Self::N> = Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize<let K: u32>(self, writer: &mut Writer<K>) {\n writer.write(self as Field);\n }\n}\n\nimpl Deserialize for u128 {\n let N: u32 = U128_SERIALIZED_LEN;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize<let K: u32>(reader: &mut Reader<K>) -> Self {\n reader.read() as u128\n }\n}\n\nimpl Serialize for Field {\n let N: u32 = FIELD_SERIALIZED_LEN;\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: Writer<Self::N> = Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize<let K: u32>(self, writer: &mut Writer<K>) {\n writer.write(self);\n }\n}\n\nimpl Deserialize for Field {\n let N: u32 = FIELD_SERIALIZED_LEN;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize<let K: u32>(reader: &mut Reader<K>) -> Self {\n reader.read()\n }\n}\n\nimpl Serialize for i8 {\n let N: u32 = I8_SERIALIZED_LEN;\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: Writer<Self::N> = Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize<let K: u32>(self, writer: &mut Writer<K>) {\n writer.write(self as u8 as Field);\n }\n}\n\nimpl Deserialize for i8 {\n let N: u32 = I8_SERIALIZED_LEN;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize<let K: u32>(reader: &mut Reader<K>) -> Self {\n reader.read() as u8 as i8\n }\n}\n\nimpl Serialize for i16 {\n let N: u32 = I16_SERIALIZED_LEN;\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: Writer<Self::N> = Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize<let K: u32>(self, writer: &mut Writer<K>) {\n writer.write(self as u16 as Field);\n }\n}\n\nimpl Deserialize for i16 {\n let N: u32 = I16_SERIALIZED_LEN;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize<let K: u32>(reader: &mut Reader<K>) -> Self {\n reader.read() as u16 as i16\n }\n}\n\nimpl Serialize for i32 {\n let N: u32 = I32_SERIALIZED_LEN;\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: Writer<Self::N> = Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize<let K: u32>(self, writer: &mut Writer<K>) {\n writer.write(self as u32 as Field);\n }\n}\n\nimpl Deserialize for i32 {\n let N: u32 = I32_SERIALIZED_LEN;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize<let K: u32>(reader: &mut Reader<K>) -> Self {\n reader.read() as u32 as i32\n }\n}\n\nimpl Serialize for i64 {\n let N: u32 = I64_SERIALIZED_LEN;\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: Writer<Self::N> = Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize<let K: u32>(self, writer: &mut Writer<K>) {\n writer.write(self as u64 as Field);\n }\n}\n\nimpl Deserialize for i64 {\n let N: u32 = I64_SERIALIZED_LEN;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize<let K: u32>(reader: &mut Reader<K>) -> Self {\n reader.read() as u64 as i64\n }\n}\n\nimpl<T, let M: u32> Serialize for [T; M]\nwhere\n T: Serialize,\n{\n let N: u32 = <T as Serialize>::N * M;\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: Writer<Self::N> = Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize<let K: u32>(self, writer: &mut Writer<K>) {\n for i in 0..M {\n self[i].stream_serialize(writer);\n }\n }\n}\n\nimpl<T, let M: u32> Deserialize for [T; M]\nwhere\n T: Deserialize,\n{\n let N: u32 = <T as Deserialize>::N * M;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize<let K: u32>(reader: &mut Reader<K>) -> Self {\n let mut result: [T; M] = std::mem::zeroed();\n for i in 0..M {\n result[i] = T::stream_deserialize(reader);\n }\n result\n }\n}\n\nimpl<T> Serialize for Option<T>\nwhere\n T: Serialize,\n{\n let N: u32 = <T as Serialize>::N + 1;\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: Writer<Self::N> = Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize<let K: u32>(self, writer: &mut Writer<K>) {\n writer.write_bool(self.is_some());\n if self.is_some() {\n self.unwrap_unchecked().stream_serialize(writer);\n } else {\n writer.advance_offset(<T as Serialize>::N);\n }\n }\n}\n\nimpl<T> Deserialize for Option<T>\nwhere\n T: Deserialize,\n{\n let N: u32 = <T as Deserialize>::N + 1;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize<let K: u32>(reader: &mut Reader<K>) -> Self {\n if reader.read_bool() {\n Option::some(<T as Deserialize>::stream_deserialize(reader))\n } else {\n reader.advance_offset(<T as Deserialize>::N);\n Option::none()\n }\n }\n}\n\nglobal SCALAR_SIZE: u32 = 2;\n\nimpl Serialize for EmbeddedCurveScalar {\n\n let N: u32 = SCALAR_SIZE;\n\n fn serialize(self) -> [Field; SCALAR_SIZE] {\n [self.lo, self.hi]\n }\n\n #[inline_always]\n fn stream_serialize<let K: u32>(self, writer: &mut Writer<K>) {\n writer.write(self.lo);\n writer.write(self.hi);\n }\n}\n\nimpl Deserialize for EmbeddedCurveScalar {\n let N: u32 = SCALAR_SIZE;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n Self { lo: fields[0], hi: fields[1] }\n }\n\n #[inline_always]\n fn stream_deserialize<let K: u32>(reader: &mut Reader<K>) -> Self {\n Self { lo: reader.read(), hi: reader.read() }\n }\n}\n\nglobal POINT_SIZE: u32 = 3;\n\nimpl Serialize for EmbeddedCurvePoint {\n let N: u32 = POINT_SIZE;\n\n fn serialize(self) -> [Field; Self::N] {\n [self.x, self.y, self.is_infinite as Field]\n }\n\n fn stream_serialize<let K: u32>(self, writer: &mut Writer<K>) {\n writer.write(self.x);\n writer.write(self.y);\n writer.write(self.is_infinite as Field);\n }\n}\n\nimpl Deserialize for EmbeddedCurvePoint {\n let N: u32 = POINT_SIZE;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n Self { x: fields[0], y: fields[1], is_infinite: fields[2] != 0 }\n }\n\n #[inline_always]\n fn stream_deserialize<let K: u32>(reader: &mut Reader<K>) -> Self {\n Self { x: reader.read(), y: reader.read(), is_infinite: reader.read_bool() }\n }\n}\n\nimpl<let M: u32> Deserialize for str<M> {\n let N: u32 = M;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize<let K: u32>(reader: &mut Reader<K>) -> Self {\n let u8_arr = <[u8; Self::N] as Deserialize>::stream_deserialize(reader);\n str::<Self::N>::from(u8_arr)\n }\n}\n\nimpl<let M: u32> Serialize for str<M> {\n let N: u32 = M;\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: Writer<Self::N> = Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize<let K: u32>(self, writer: &mut Writer<K>) {\n self.as_bytes().stream_serialize(writer);\n }\n}\n\n// Note: Not deriving this because it's not supported to call derive_serialize on a \"remote\" struct (and it will never\n// be supported).\nimpl<T, let M: u32> Deserialize for BoundedVec<T, M>\nwhere\n T: Deserialize,\n{\n let N: u32 = <T as Deserialize>::N * M + 1;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize<let K: u32>(reader: &mut Reader<K>) -> Self {\n let mut new_bounded_vec: BoundedVec<T, M> = BoundedVec::new();\n let payload_len = Self::N - 1;\n\n // Length is stored in the last field as we need to match intrinsic Noir serialization and the `len` struct\n // field is after `storage` struct field (see `bounded_vec.nr` in noir-stdlib)\n let len = reader.peek_offset(payload_len) as u32;\n\n for i in 0..M {\n if i < len {\n new_bounded_vec.push(<T as Deserialize>::stream_deserialize(reader));\n }\n }\n\n // +1 for the length of the BoundedVec\n reader.advance_offset((M - len) * <T as Deserialize>::N + 1);\n\n new_bounded_vec\n }\n}\n\n// This may cause issues if used as program input, because noir disallows empty arrays for program input.\n// I think this is okay because I don't foresee a unit type being used as input. But leaving this comment as a hint\n// if someone does run into this in the future.\nimpl Deserialize for () {\n let N: u32 = 0;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize<let K: u32>(_reader: &mut Reader<K>) -> Self {\n ()\n }\n}\n\n// Note: Not deriving this because it's not supported to call derive_serialize on a \"remote\" struct (and it will never\n// be supported).\nimpl<T, let M: u32> Serialize for BoundedVec<T, M>\nwhere\n T: Serialize,\n{\n let N: u32 = <T as Serialize>::N * M + 1; // +1 for the length of the BoundedVec\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: Writer<Self::N> = Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize<let K: u32>(self, writer: &mut Writer<K>) {\n self.storage().stream_serialize(writer);\n // Length is stored in the last field as we need to match intrinsic Noir serialization and the `len` struct\n // field is after `storage` struct field (see `bounded_vec.nr` in noir-stdlib)\n writer.write_u32(self.len() as u32);\n }\n}\n\n// Create a slice of the given length with each element made from `f(i)` where `i` is the current index\ncomptime fn make_slice<Env, T>(length: u32, f: fn[Env](u32) -> T) -> [T] {\n let mut slice = @[];\n for i in 0..length {\n slice = slice.push_back(f(i));\n }\n slice\n}\n\n// Implements Serialize and Deserialize for an arbitrary tuple type\ncomptime fn impl_serialize_for_tuple(_m: Module, length: u32) -> Quoted {\n // `T0`, `T1`, `T2`\n let type_names = make_slice(length, |i| f\"T{i}\".quoted_contents());\n\n // `result0`, `result1`, `result2`\n let result_names = make_slice(length, |i| f\"result{i}\".quoted_contents());\n\n // `T0, T1, T2`\n let field_generics = type_names.join(quote [,]);\n\n // `<T0 as Serialize>::N + <T1 as Serialize>::N + <T2 as Serialize>::N`\n let full_size_serialize = type_names\n .map(|type_name| quote {\n <$type_name as Serialize>::N\n })\n .join(quote [+]);\n\n // `<T0 as Deserialize>::N + <T1 as Deserialize>::N + <T2 as Deserialize>::N`\n let full_size_deserialize = type_names\n .map(|type_name| quote {\n <$type_name as Deserialize>::N\n })\n .join(quote [+]);\n\n // `T0: Serialize, T1: Serialize, T2: Serialize,`\n let serialize_constraints = type_names\n .map(|field_name| quote {\n $field_name: Serialize,\n })\n .join(quote []);\n\n // `T0: Deserialize, T1: Deserialize, T2: Deserialize,`\n let deserialize_constraints = type_names\n .map(|field_name| quote {\n $field_name: Deserialize,\n })\n .join(quote []);\n\n // Statements to serialize each field\n let serialized_fields = type_names\n .mapi(|i, _type_name| quote {\n $crate::serialization::Serialize::stream_serialize(self.$i, writer);\n })\n .join(quote []);\n\n // Statements to deserialize each field\n let deserialized_fields = type_names\n .mapi(|i, type_name| {\n let result_name = result_names[i];\n quote {\n let $result_name = <$type_name as $crate::serialization::Deserialize>::stream_deserialize(reader);\n }\n })\n .join(quote []);\n let deserialize_results = result_names.join(quote [,]);\n\n quote {\n impl<$field_generics> Serialize for ($field_generics) where $serialize_constraints {\n let N: u32 = $full_size_serialize;\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: $crate::writer::Writer<Self::N> = $crate::writer::Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize<let K: u32>(self, writer: &mut $crate::writer::Writer<K>) {\n\n $serialized_fields\n }\n }\n\n impl<$field_generics> Deserialize for ($field_generics) where $deserialize_constraints {\n let N: u32 = $full_size_deserialize;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = $crate::reader::Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n \n #[inline_always]\n fn stream_deserialize<let K: u32>(reader: &mut $crate::reader::Reader<K>) -> Self {\n $deserialized_fields\n ($deserialize_results)\n }\n }\n }\n}\n\n// Keeping these manual impls. They are more efficient since they do not\n// require copying sub-arrays from any serialized arrays.\nimpl<T1> Serialize for (T1,)\nwhere\n T1: Serialize,\n{\n let N: u32 = <T1 as Serialize>::N;\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: crate::writer::Writer<Self::N> = crate::writer::Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize<let K: u32>(self, writer: &mut Writer<K>) {\n self.0.stream_serialize(writer);\n }\n}\n\nimpl<T1> Deserialize for (T1,)\nwhere\n T1: Deserialize,\n{\n let N: u32 = <T1 as Deserialize>::N;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = crate::reader::Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize<let K: u32>(reader: &mut Reader<K>) -> Self {\n (<T1 as Deserialize>::stream_deserialize(reader),)\n }\n}\n\n#[impl_serialize_for_tuple(2)]\n#[impl_serialize_for_tuple(3)]\n#[impl_serialize_for_tuple(4)]\n#[impl_serialize_for_tuple(5)]\n#[impl_serialize_for_tuple(6)]\nmod impls {\n use crate::serialization::{Deserialize, Serialize};\n}\n\n#[test]\nunconstrained fn bounded_vec_serialization() {\n // Test empty BoundedVec\n let empty_vec: BoundedVec<Field, 3> = BoundedVec::from_array([]);\n let serialized = empty_vec.serialize();\n let deserialized = BoundedVec::<Field, 3>::deserialize(serialized);\n assert_eq(empty_vec, deserialized);\n assert_eq(deserialized.len(), 0);\n\n // Test partially filled BoundedVec\n let partial_vec: BoundedVec<[u32; 2], 3> = BoundedVec::from_array([[1, 2]]);\n let serialized = partial_vec.serialize();\n let deserialized = BoundedVec::<[u32; 2], 3>::deserialize(serialized);\n assert_eq(partial_vec, deserialized);\n assert_eq(deserialized.len(), 1);\n assert_eq(deserialized.get(0), [1, 2]);\n\n // Test full BoundedVec\n let full_vec: BoundedVec<[u32; 2], 3> = BoundedVec::from_array([[1, 2], [3, 4], [5, 6]]);\n let serialized = full_vec.serialize();\n let deserialized = BoundedVec::<[u32; 2], 3>::deserialize(serialized);\n assert_eq(full_vec, deserialized);\n assert_eq(deserialized.len(), 3);\n assert_eq(deserialized.get(0), [1, 2]);\n assert_eq(deserialized.get(1), [3, 4]);\n assert_eq(deserialized.get(2), [5, 6]);\n}\n"
6122
+ "source": "use crate::{reader::Reader, serialization::{Deserialize, Serialize}, writer::Writer};\nuse std::embedded_curve_ops::EmbeddedCurvePoint;\nuse std::embedded_curve_ops::EmbeddedCurveScalar;\n\nglobal BOOL_SERIALIZED_LEN: u32 = 1;\nglobal U8_SERIALIZED_LEN: u32 = 1;\nglobal U16_SERIALIZED_LEN: u32 = 1;\nglobal U32_SERIALIZED_LEN: u32 = 1;\nglobal U64_SERIALIZED_LEN: u32 = 1;\nglobal U128_SERIALIZED_LEN: u32 = 1;\nglobal FIELD_SERIALIZED_LEN: u32 = 1;\nglobal I8_SERIALIZED_LEN: u32 = 1;\nglobal I16_SERIALIZED_LEN: u32 = 1;\nglobal I32_SERIALIZED_LEN: u32 = 1;\nglobal I64_SERIALIZED_LEN: u32 = 1;\n\nimpl Serialize for bool {\n let N: u32 = BOOL_SERIALIZED_LEN;\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: Writer<Self::N> = Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize<let K: u32>(self, writer: &mut Writer<K>) {\n writer.write(self as Field);\n }\n}\n\nimpl Deserialize for bool {\n let N: u32 = BOOL_SERIALIZED_LEN;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize<let K: u32>(reader: &mut Reader<K>) -> bool {\n reader.read() != 0\n }\n}\n\nimpl Serialize for u8 {\n let N: u32 = U8_SERIALIZED_LEN;\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: Writer<Self::N> = Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize<let K: u32>(self, writer: &mut Writer<K>) {\n writer.write(self as Field);\n }\n}\n\nimpl Deserialize for u8 {\n let N: u32 = U8_SERIALIZED_LEN;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize<let K: u32>(reader: &mut Reader<K>) -> Self {\n reader.read() as u8\n }\n}\n\nimpl Serialize for u16 {\n let N: u32 = U16_SERIALIZED_LEN;\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: Writer<Self::N> = Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize<let K: u32>(self, writer: &mut Writer<K>) {\n writer.write(self as Field);\n }\n}\n\nimpl Deserialize for u16 {\n let N: u32 = U16_SERIALIZED_LEN;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize<let K: u32>(reader: &mut Reader<K>) -> Self {\n reader.read() as u16\n }\n}\n\nimpl Serialize for u32 {\n let N: u32 = U32_SERIALIZED_LEN;\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: Writer<Self::N> = Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize<let K: u32>(self, writer: &mut Writer<K>) {\n writer.write(self as Field);\n }\n}\n\nimpl Deserialize for u32 {\n let N: u32 = U32_SERIALIZED_LEN;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize<let K: u32>(reader: &mut Reader<K>) -> Self {\n reader.read() as u32\n }\n}\n\nimpl Serialize for u64 {\n let N: u32 = U64_SERIALIZED_LEN;\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: Writer<Self::N> = Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize<let K: u32>(self, writer: &mut Writer<K>) {\n writer.write(self as Field);\n }\n}\n\nimpl Deserialize for u64 {\n let N: u32 = U64_SERIALIZED_LEN;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize<let K: u32>(reader: &mut Reader<K>) -> Self {\n reader.read() as u64\n }\n}\n\nimpl Serialize for u128 {\n let N: u32 = U128_SERIALIZED_LEN;\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: Writer<Self::N> = Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize<let K: u32>(self, writer: &mut Writer<K>) {\n writer.write(self as Field);\n }\n}\n\nimpl Deserialize for u128 {\n let N: u32 = U128_SERIALIZED_LEN;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize<let K: u32>(reader: &mut Reader<K>) -> Self {\n reader.read() as u128\n }\n}\n\nimpl Serialize for Field {\n let N: u32 = FIELD_SERIALIZED_LEN;\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: Writer<Self::N> = Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize<let K: u32>(self, writer: &mut Writer<K>) {\n writer.write(self);\n }\n}\n\nimpl Deserialize for Field {\n let N: u32 = FIELD_SERIALIZED_LEN;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize<let K: u32>(reader: &mut Reader<K>) -> Self {\n reader.read()\n }\n}\n\nimpl Serialize for i8 {\n let N: u32 = I8_SERIALIZED_LEN;\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: Writer<Self::N> = Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize<let K: u32>(self, writer: &mut Writer<K>) {\n writer.write(self as u8 as Field);\n }\n}\n\nimpl Deserialize for i8 {\n let N: u32 = I8_SERIALIZED_LEN;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize<let K: u32>(reader: &mut Reader<K>) -> Self {\n reader.read() as u8 as i8\n }\n}\n\nimpl Serialize for i16 {\n let N: u32 = I16_SERIALIZED_LEN;\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: Writer<Self::N> = Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize<let K: u32>(self, writer: &mut Writer<K>) {\n writer.write(self as u16 as Field);\n }\n}\n\nimpl Deserialize for i16 {\n let N: u32 = I16_SERIALIZED_LEN;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize<let K: u32>(reader: &mut Reader<K>) -> Self {\n reader.read() as u16 as i16\n }\n}\n\nimpl Serialize for i32 {\n let N: u32 = I32_SERIALIZED_LEN;\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: Writer<Self::N> = Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize<let K: u32>(self, writer: &mut Writer<K>) {\n writer.write(self as u32 as Field);\n }\n}\n\nimpl Deserialize for i32 {\n let N: u32 = I32_SERIALIZED_LEN;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize<let K: u32>(reader: &mut Reader<K>) -> Self {\n reader.read() as u32 as i32\n }\n}\n\nimpl Serialize for i64 {\n let N: u32 = I64_SERIALIZED_LEN;\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: Writer<Self::N> = Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize<let K: u32>(self, writer: &mut Writer<K>) {\n writer.write(self as u64 as Field);\n }\n}\n\nimpl Deserialize for i64 {\n let N: u32 = I64_SERIALIZED_LEN;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize<let K: u32>(reader: &mut Reader<K>) -> Self {\n reader.read() as u64 as i64\n }\n}\n\nimpl<T, let M: u32> Serialize for [T; M]\nwhere\n T: Serialize,\n{\n let N: u32 = <T as Serialize>::N * M;\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: Writer<Self::N> = Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize<let K: u32>(self, writer: &mut Writer<K>) {\n for i in 0..M {\n self[i].stream_serialize(writer);\n }\n }\n}\n\nimpl<T, let M: u32> Deserialize for [T; M]\nwhere\n T: Deserialize,\n{\n let N: u32 = <T as Deserialize>::N * M;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize<let K: u32>(reader: &mut Reader<K>) -> Self {\n let mut result: [T; M] = std::mem::zeroed();\n for i in 0..M {\n result[i] = T::stream_deserialize(reader);\n }\n result\n }\n}\n\nimpl<T> Serialize for Option<T>\nwhere\n T: Serialize,\n{\n let N: u32 = <T as Serialize>::N + 1;\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: Writer<Self::N> = Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize<let K: u32>(self, writer: &mut Writer<K>) {\n writer.write_bool(self.is_some());\n if self.is_some() {\n self.unwrap_unchecked().stream_serialize(writer);\n } else {\n writer.advance_offset(<T as Serialize>::N);\n }\n }\n}\n\nimpl<T> Deserialize for Option<T>\nwhere\n T: Deserialize,\n{\n let N: u32 = <T as Deserialize>::N + 1;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize<let K: u32>(reader: &mut Reader<K>) -> Self {\n if reader.read_bool() {\n Option::some(<T as Deserialize>::stream_deserialize(reader))\n } else {\n reader.advance_offset(<T as Deserialize>::N);\n Option::none()\n }\n }\n}\n\nglobal SCALAR_SIZE: u32 = 2;\n\nimpl Serialize for EmbeddedCurveScalar {\n\n let N: u32 = SCALAR_SIZE;\n\n fn serialize(self) -> [Field; SCALAR_SIZE] {\n [self.lo, self.hi]\n }\n\n #[inline_always]\n fn stream_serialize<let K: u32>(self, writer: &mut Writer<K>) {\n writer.write(self.lo);\n writer.write(self.hi);\n }\n}\n\nimpl Deserialize for EmbeddedCurveScalar {\n let N: u32 = SCALAR_SIZE;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n Self { lo: fields[0], hi: fields[1] }\n }\n\n #[inline_always]\n fn stream_deserialize<let K: u32>(reader: &mut Reader<K>) -> Self {\n Self { lo: reader.read(), hi: reader.read() }\n }\n}\n\nglobal POINT_SIZE: u32 = 2;\n\nimpl Serialize for EmbeddedCurvePoint {\n let N: u32 = POINT_SIZE;\n\n fn serialize(self) -> [Field; Self::N] {\n [self.x, self.y]\n }\n\n fn stream_serialize<let K: u32>(self, writer: &mut Writer<K>) {\n writer.write(self.x);\n writer.write(self.y);\n }\n}\n\nimpl Deserialize for EmbeddedCurvePoint {\n let N: u32 = POINT_SIZE;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n Self { x: fields[0], y: fields[1] }\n }\n\n #[inline_always]\n fn stream_deserialize<let K: u32>(reader: &mut Reader<K>) -> Self {\n Self { x: reader.read(), y: reader.read() }\n }\n}\n\nimpl<let M: u32> Deserialize for str<M> {\n let N: u32 = M;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize<let K: u32>(reader: &mut Reader<K>) -> Self {\n let u8_arr = <[u8; Self::N] as Deserialize>::stream_deserialize(reader);\n str::<Self::N>::from(u8_arr)\n }\n}\n\nimpl<let M: u32> Serialize for str<M> {\n let N: u32 = M;\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: Writer<Self::N> = Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize<let K: u32>(self, writer: &mut Writer<K>) {\n self.as_bytes().stream_serialize(writer);\n }\n}\n\n// Note: Not deriving this because it's not supported to call derive_serialize on a \"remote\" struct (and it will never\n// be supported).\nimpl<T, let M: u32> Deserialize for BoundedVec<T, M>\nwhere\n T: Deserialize,\n{\n let N: u32 = <T as Deserialize>::N * M + 1;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize<let K: u32>(reader: &mut Reader<K>) -> Self {\n let mut new_bounded_vec: BoundedVec<T, M> = BoundedVec::new();\n let payload_len = Self::N - 1;\n\n // Length is stored in the last field as we need to match intrinsic Noir serialization and the `len` struct\n // field is after `storage` struct field (see `bounded_vec.nr` in noir-stdlib)\n let len = reader.peek_offset(payload_len) as u32;\n\n for i in 0..M {\n if i < len {\n new_bounded_vec.push(<T as Deserialize>::stream_deserialize(reader));\n }\n }\n\n // +1 for the length of the BoundedVec\n reader.advance_offset((M - len) * <T as Deserialize>::N + 1);\n\n new_bounded_vec\n }\n}\n\n// This may cause issues if used as program input, because noir disallows empty arrays for program input.\n// I think this is okay because I don't foresee a unit type being used as input. But leaving this comment as a hint\n// if someone does run into this in the future.\nimpl Deserialize for () {\n let N: u32 = 0;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize<let K: u32>(_reader: &mut Reader<K>) -> Self {\n ()\n }\n}\n\n// Note: Not deriving this because it's not supported to call derive_serialize on a \"remote\" struct (and it will never\n// be supported).\nimpl<T, let M: u32> Serialize for BoundedVec<T, M>\nwhere\n T: Serialize,\n{\n let N: u32 = <T as Serialize>::N * M + 1; // +1 for the length of the BoundedVec\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: Writer<Self::N> = Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize<let K: u32>(self, writer: &mut Writer<K>) {\n self.storage().stream_serialize(writer);\n // Length is stored in the last field as we need to match intrinsic Noir serialization and the `len` struct\n // field is after `storage` struct field (see `bounded_vec.nr` in noir-stdlib)\n writer.write_u32(self.len() as u32);\n }\n}\n\n// Create a slice of the given length with each element made from `f(i)` where `i` is the current index\ncomptime fn make_slice<Env, T>(length: u32, f: fn[Env](u32) -> T) -> [T] {\n let mut slice = @[];\n for i in 0..length {\n slice = slice.push_back(f(i));\n }\n slice\n}\n\n// Implements Serialize and Deserialize for an arbitrary tuple type\ncomptime fn impl_serialize_for_tuple(_m: Module, length: u32) -> Quoted {\n // `T0`, `T1`, `T2`\n let type_names = make_slice(length, |i| f\"T{i}\".quoted_contents());\n\n // `result0`, `result1`, `result2`\n let result_names = make_slice(length, |i| f\"result{i}\".quoted_contents());\n\n // `T0, T1, T2`\n let field_generics = type_names.join(quote [,]);\n\n // `<T0 as Serialize>::N + <T1 as Serialize>::N + <T2 as Serialize>::N`\n let full_size_serialize = type_names\n .map(|type_name| quote {\n <$type_name as Serialize>::N\n })\n .join(quote [+]);\n\n // `<T0 as Deserialize>::N + <T1 as Deserialize>::N + <T2 as Deserialize>::N`\n let full_size_deserialize = type_names\n .map(|type_name| quote {\n <$type_name as Deserialize>::N\n })\n .join(quote [+]);\n\n // `T0: Serialize, T1: Serialize, T2: Serialize,`\n let serialize_constraints = type_names\n .map(|field_name| quote {\n $field_name: Serialize,\n })\n .join(quote []);\n\n // `T0: Deserialize, T1: Deserialize, T2: Deserialize,`\n let deserialize_constraints = type_names\n .map(|field_name| quote {\n $field_name: Deserialize,\n })\n .join(quote []);\n\n // Statements to serialize each field\n let serialized_fields = type_names\n .mapi(|i, _type_name| quote {\n $crate::serialization::Serialize::stream_serialize(self.$i, writer);\n })\n .join(quote []);\n\n // Statements to deserialize each field\n let deserialized_fields = type_names\n .mapi(|i, type_name| {\n let result_name = result_names[i];\n quote {\n let $result_name = <$type_name as $crate::serialization::Deserialize>::stream_deserialize(reader);\n }\n })\n .join(quote []);\n let deserialize_results = result_names.join(quote [,]);\n\n quote {\n impl<$field_generics> Serialize for ($field_generics) where $serialize_constraints {\n let N: u32 = $full_size_serialize;\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: $crate::writer::Writer<Self::N> = $crate::writer::Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize<let K: u32>(self, writer: &mut $crate::writer::Writer<K>) {\n\n $serialized_fields\n }\n }\n\n impl<$field_generics> Deserialize for ($field_generics) where $deserialize_constraints {\n let N: u32 = $full_size_deserialize;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = $crate::reader::Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n \n #[inline_always]\n fn stream_deserialize<let K: u32>(reader: &mut $crate::reader::Reader<K>) -> Self {\n $deserialized_fields\n ($deserialize_results)\n }\n }\n }\n}\n\n// Keeping these manual impls. They are more efficient since they do not\n// require copying sub-arrays from any serialized arrays.\nimpl<T1> Serialize for (T1,)\nwhere\n T1: Serialize,\n{\n let N: u32 = <T1 as Serialize>::N;\n\n fn serialize(self) -> [Field; Self::N] {\n let mut writer: crate::writer::Writer<Self::N> = crate::writer::Writer::new();\n self.stream_serialize(&mut writer);\n writer.finish()\n }\n\n #[inline_always]\n fn stream_serialize<let K: u32>(self, writer: &mut Writer<K>) {\n self.0.stream_serialize(writer);\n }\n}\n\nimpl<T1> Deserialize for (T1,)\nwhere\n T1: Deserialize,\n{\n let N: u32 = <T1 as Deserialize>::N;\n\n fn deserialize(fields: [Field; Self::N]) -> Self {\n let mut reader = crate::reader::Reader::new(fields);\n let result = Self::stream_deserialize(&mut reader);\n reader.finish();\n result\n }\n\n #[inline_always]\n fn stream_deserialize<let K: u32>(reader: &mut Reader<K>) -> Self {\n (<T1 as Deserialize>::stream_deserialize(reader),)\n }\n}\n\n#[impl_serialize_for_tuple(2)]\n#[impl_serialize_for_tuple(3)]\n#[impl_serialize_for_tuple(4)]\n#[impl_serialize_for_tuple(5)]\n#[impl_serialize_for_tuple(6)]\nmod impls {\n use crate::serialization::{Deserialize, Serialize};\n}\n\n#[test]\nunconstrained fn bounded_vec_serialization() {\n // Test empty BoundedVec\n let empty_vec: BoundedVec<Field, 3> = BoundedVec::from_array([]);\n let serialized = empty_vec.serialize();\n let deserialized = BoundedVec::<Field, 3>::deserialize(serialized);\n assert_eq(empty_vec, deserialized);\n assert_eq(deserialized.len(), 0);\n\n // Test partially filled BoundedVec\n let partial_vec: BoundedVec<[u32; 2], 3> = BoundedVec::from_array([[1, 2]]);\n let serialized = partial_vec.serialize();\n let deserialized = BoundedVec::<[u32; 2], 3>::deserialize(serialized);\n assert_eq(partial_vec, deserialized);\n assert_eq(deserialized.len(), 1);\n assert_eq(deserialized.get(0), [1, 2]);\n\n // Test full BoundedVec\n let full_vec: BoundedVec<[u32; 2], 3> = BoundedVec::from_array([[1, 2], [3, 4], [5, 6]]);\n let serialized = full_vec.serialize();\n let deserialized = BoundedVec::<[u32; 2], 3>::deserialize(serialized);\n assert_eq(full_vec, deserialized);\n assert_eq(deserialized.len(), 3);\n assert_eq(deserialized.get(0), [1, 2]);\n assert_eq(deserialized.get(1), [3, 4]);\n assert_eq(deserialized.get(2), [5, 6]);\n}\n"
6147
6123
  },
6148
6124
  "413": {
6149
6125
  "function_locations": [
@@ -6231,241 +6207,237 @@
6231
6207
  "name": "<impl Eq for u8>::eq",
6232
6208
  "start": 1282
6233
6209
  },
6234
- {
6235
- "name": "<impl Eq for u1>::eq",
6236
- "start": 1366
6237
- },
6238
6210
  {
6239
6211
  "name": "<impl Eq for i8>::eq",
6240
- "start": 1451
6212
+ "start": 1366
6241
6213
  },
6242
6214
  {
6243
6215
  "name": "<impl Eq for i16>::eq",
6244
- "start": 1537
6216
+ "start": 1452
6245
6217
  },
6246
6218
  {
6247
6219
  "name": "<impl Eq for i32>::eq",
6248
- "start": 1623
6220
+ "start": 1538
6249
6221
  },
6250
6222
  {
6251
6223
  "name": "<impl Eq for i64>::eq",
6252
- "start": 1709
6224
+ "start": 1624
6253
6225
  },
6254
6226
  {
6255
6227
  "name": "<impl Eq for ()>::eq",
6256
- "start": 1802
6228
+ "start": 1717
6257
6229
  },
6258
6230
  {
6259
6231
  "name": "<impl Eq for bool>::eq",
6260
- "start": 1881
6232
+ "start": 1796
6261
6233
  },
6262
6234
  {
6263
6235
  "name": "<impl Eq for [T; N]>::eq",
6264
- "start": 2006
6236
+ "start": 1921
6265
6237
  },
6266
6238
  {
6267
6239
  "name": "<impl Eq for [T]>::eq",
6268
- "start": 2224
6240
+ "start": 2139
6269
6241
  },
6270
6242
  {
6271
6243
  "name": "<impl Eq for str<N>>::eq",
6272
- "start": 2503
6244
+ "start": 2418
6273
6245
  },
6274
6246
  {
6275
6247
  "name": "make_tuple_eq_body",
6276
- "start": 2683
6248
+ "start": 2598
6277
6249
  },
6278
6250
  {
6279
6251
  "name": "<impl Eq for (A, B)>::eq",
6280
- "start": 2944
6252
+ "start": 2859
6281
6253
  },
6282
6254
  {
6283
6255
  "name": "<impl Eq for (A, B, C)>::eq",
6284
- "start": 3076
6256
+ "start": 2991
6285
6257
  },
6286
6258
  {
6287
6259
  "name": "<impl Eq for (A, B, C, D)>::eq",
6288
- "start": 3221
6260
+ "start": 3136
6289
6261
  },
6290
6262
  {
6291
6263
  "name": "<impl Eq for (A, B, C, D, E)>::eq",
6292
- "start": 3379
6264
+ "start": 3294
6293
6265
  },
6294
6266
  {
6295
6267
  "name": "<impl Eq for (A, B, C, D, E, F)>::eq",
6296
- "start": 3550
6268
+ "start": 3465
6297
6269
  },
6298
6270
  {
6299
6271
  "name": "<impl Eq for (A, B, C, D, E, F, G)>::eq",
6300
- "start": 3734
6272
+ "start": 3649
6301
6273
  },
6302
6274
  {
6303
6275
  "name": "<impl Eq for (A, B, C, D, E, F, G, H)>::eq",
6304
- "start": 3931
6276
+ "start": 3846
6305
6277
  },
6306
6278
  {
6307
6279
  "name": "<impl Eq for (A, B, C, D, E, F, G, H, I)>::eq",
6308
- "start": 4141
6280
+ "start": 4056
6309
6281
  },
6310
6282
  {
6311
6283
  "name": "<impl Eq for (A, B, C, D, E, F, G, H, I, J)>::eq",
6312
- "start": 4364
6284
+ "start": 4279
6313
6285
  },
6314
6286
  {
6315
6287
  "name": "<impl Eq for (A, B, C, D, E, F, G, H, I, J, K)>::eq",
6316
- "start": 4601
6288
+ "start": 4516
6317
6289
  },
6318
6290
  {
6319
6291
  "name": "<impl Eq for (A, B, C, D, E, F, G, H, I, J, K, L)>::eq",
6320
- "start": 4851
6292
+ "start": 4766
6321
6293
  },
6322
6294
  {
6323
6295
  "name": "<impl Eq for Ordering>::eq",
6324
- "start": 4961
6296
+ "start": 4876
6325
6297
  },
6326
6298
  {
6327
6299
  "name": "Ordering::less",
6328
- "start": 5562
6300
+ "start": 5477
6329
6301
  },
6330
6302
  {
6331
6303
  "name": "Ordering::equal",
6332
- "start": 5633
6304
+ "start": 5548
6333
6305
  },
6334
6306
  {
6335
6307
  "name": "Ordering::greater",
6336
- "start": 5706
6308
+ "start": 5621
6337
6309
  },
6338
6310
  {
6339
6311
  "name": "derive_ord",
6340
- "start": 6077
6312
+ "start": 5992
6341
6313
  },
6342
6314
  {
6343
6315
  "name": "<impl Ord for u128>::cmp",
6344
- "start": 6727
6316
+ "start": 6642
6345
6317
  },
6346
6318
  {
6347
6319
  "name": "<impl Ord for u64>::cmp",
6348
- "start": 6974
6320
+ "start": 6889
6349
6321
  },
6350
6322
  {
6351
6323
  "name": "<impl Ord for u32>::cmp",
6352
- "start": 7222
6324
+ "start": 7137
6353
6325
  },
6354
6326
  {
6355
6327
  "name": "<impl Ord for u16>::cmp",
6356
- "start": 7470
6328
+ "start": 7385
6357
6329
  },
6358
6330
  {
6359
6331
  "name": "<impl Ord for u8>::cmp",
6360
- "start": 7716
6332
+ "start": 7631
6361
6333
  },
6362
6334
  {
6363
6335
  "name": "<impl Ord for i8>::cmp",
6364
- "start": 7962
6336
+ "start": 7877
6365
6337
  },
6366
6338
  {
6367
6339
  "name": "<impl Ord for i16>::cmp",
6368
- "start": 8210
6340
+ "start": 8125
6369
6341
  },
6370
6342
  {
6371
6343
  "name": "<impl Ord for i32>::cmp",
6372
- "start": 8458
6344
+ "start": 8373
6373
6345
  },
6374
6346
  {
6375
6347
  "name": "<impl Ord for i64>::cmp",
6376
- "start": 8706
6348
+ "start": 8621
6377
6349
  },
6378
6350
  {
6379
6351
  "name": "<impl Ord for ()>::cmp",
6380
- "start": 8960
6352
+ "start": 8875
6381
6353
  },
6382
6354
  {
6383
6355
  "name": "<impl Ord for bool>::cmp",
6384
- "start": 9059
6356
+ "start": 8974
6385
6357
  },
6386
6358
  {
6387
6359
  "name": "<impl Ord for [T; N]>::cmp",
6388
- "start": 9529
6360
+ "start": 9444
6389
6361
  },
6390
6362
  {
6391
6363
  "name": "<impl Ord for [T]>::cmp",
6392
- "start": 9932
6364
+ "start": 9847
6393
6365
  },
6394
6366
  {
6395
6367
  "name": "make_tuple_ord_body",
6396
- "start": 10500
6368
+ "start": 10415
6397
6369
  },
6398
6370
  {
6399
6371
  "name": "<impl Ord for (A, B)>::cmp",
6400
- "start": 11122
6372
+ "start": 11037
6401
6373
  },
6402
6374
  {
6403
6375
  "name": "<impl Ord for (A, B, C)>::cmp",
6404
- "start": 11264
6376
+ "start": 11179
6405
6377
  },
6406
6378
  {
6407
6379
  "name": "<impl Ord for (A, B, C, D)>::cmp",
6408
- "start": 11420
6380
+ "start": 11335
6409
6381
  },
6410
6382
  {
6411
6383
  "name": "<impl Ord for (A, B, C, D, E)>::cmp",
6412
- "start": 11590
6384
+ "start": 11505
6413
6385
  },
6414
6386
  {
6415
6387
  "name": "<impl Ord for (A, B, C, D, E, F)>::cmp",
6416
- "start": 11774
6388
+ "start": 11689
6417
6389
  },
6418
6390
  {
6419
6391
  "name": "<impl Ord for (A, B, C, D, E, F, G)>::cmp",
6420
- "start": 11972
6392
+ "start": 11887
6421
6393
  },
6422
6394
  {
6423
6395
  "name": "<impl Ord for (A, B, C, D, E, F, G, H)>::cmp",
6424
- "start": 12184
6396
+ "start": 12099
6425
6397
  },
6426
6398
  {
6427
6399
  "name": "<impl Ord for (A, B, C, D, E, F, G, H, I)>::cmp",
6428
- "start": 12410
6400
+ "start": 12325
6429
6401
  },
6430
6402
  {
6431
6403
  "name": "<impl Ord for (A, B, C, D, E, F, G, H, I, J)>::cmp",
6432
- "start": 12650
6404
+ "start": 12565
6433
6405
  },
6434
6406
  {
6435
6407
  "name": "<impl Ord for (A, B, C, D, E, F, G, H, I, J, K)>::cmp",
6436
- "start": 12905
6408
+ "start": 12820
6437
6409
  },
6438
6410
  {
6439
6411
  "name": "<impl Ord for (A, B, C, D, E, F, G, H, I, J, K, L)>::cmp",
6440
- "start": 13174
6412
+ "start": 13089
6441
6413
  },
6442
6414
  {
6443
6415
  "name": "max",
6444
- "start": 13536
6416
+ "start": 13451
6445
6417
  },
6446
6418
  {
6447
6419
  "name": "min",
6448
- "start": 13913
6420
+ "start": 13828
6449
6421
  },
6450
6422
  {
6451
6423
  "name": "cmp_tests::sanity_check_min",
6452
- "start": 14067
6424
+ "start": 13982
6453
6425
  },
6454
6426
  {
6455
6427
  "name": "cmp_tests::sanity_check_max",
6456
- "start": 14263
6428
+ "start": 14178
6457
6429
  },
6458
6430
  {
6459
6431
  "name": "cmp_tests::correctly_handles_unequal_length_vectors",
6460
- "start": 14485
6432
+ "start": 14400
6461
6433
  },
6462
6434
  {
6463
6435
  "name": "cmp_tests::lexicographic_ordering_for_vectors",
6464
- "start": 14685
6436
+ "start": 14600
6465
6437
  }
6466
6438
  ],
6467
6439
  "path": "std/cmp.nr",
6468
- "source": "use crate::meta::ctstring::AsCtString;\nuse crate::meta::derive_via;\n\n/// Compare two values for equality\n#[derive_via(derive_eq)]\n// docs:start:eq-trait\npub trait Eq {\n fn eq(self, other: Self) -> bool;\n}\n// docs:end:eq-trait\n\n// docs:start:derive_eq\ncomptime fn derive_eq(s: TypeDefinition) -> Quoted {\n let signature = quote { fn eq(_self: Self, _other: Self) -> bool };\n let for_each_field = |name| quote { (_self.$name == _other.$name) };\n let body = |fields| {\n if s.fields_as_written().len() == 0 {\n quote { true }\n } else {\n fields\n }\n };\n crate::meta::make_trait_impl(\n s,\n quote { $crate::cmp::Eq },\n signature,\n for_each_field,\n quote { & },\n body,\n )\n}\n// docs:end:derive_eq\n\nimpl Eq for Field {\n fn eq(self, other: Field) -> bool {\n self == other\n }\n}\n\nimpl Eq for u128 {\n fn eq(self, other: u128) -> bool {\n self == other\n }\n}\nimpl Eq for u64 {\n fn eq(self, other: u64) -> bool {\n self == other\n }\n}\nimpl Eq for u32 {\n fn eq(self, other: u32) -> bool {\n self == other\n }\n}\nimpl Eq for u16 {\n fn eq(self, other: u16) -> bool {\n self == other\n }\n}\nimpl Eq for u8 {\n fn eq(self, other: u8) -> bool {\n self == other\n }\n}\nimpl Eq for u1 {\n fn eq(self, other: u1) -> bool {\n self == other\n }\n}\n\nimpl Eq for i8 {\n fn eq(self, other: i8) -> bool {\n self == other\n }\n}\nimpl Eq for i16 {\n fn eq(self, other: i16) -> bool {\n self == other\n }\n}\nimpl Eq for i32 {\n fn eq(self, other: i32) -> bool {\n self == other\n }\n}\nimpl Eq for i64 {\n fn eq(self, other: i64) -> bool {\n self == other\n }\n}\n\nimpl Eq for () {\n fn eq(_self: Self, _other: ()) -> bool {\n true\n }\n}\nimpl Eq for bool {\n fn eq(self, other: bool) -> bool {\n self == other\n }\n}\n\nimpl<T, let N: u32> Eq for [T; N]\nwhere\n T: Eq,\n{\n fn eq(self, other: [T; N]) -> bool {\n let mut result = true;\n for i in 0..self.len() {\n result &= self[i].eq(other[i]);\n }\n result\n }\n}\n\nimpl<T> Eq for [T]\nwhere\n T: Eq,\n{\n fn eq(self, other: [T]) -> bool {\n let mut result = self.len() == other.len();\n if result {\n for i in 0..self.len() {\n result &= self[i].eq(other[i]);\n }\n }\n result\n }\n}\n\nimpl<let N: u32> Eq for str<N> {\n fn eq(self, other: str<N>) -> bool {\n let self_bytes = self.as_bytes();\n let other_bytes = other.as_bytes();\n self_bytes == other_bytes\n }\n}\n\ncomptime fn make_tuple_eq_body(n: u32) -> Quoted {\n let mut body = f\"self.0.eq(other.0)\".as_ctstring();\n for i in 1u32..n {\n body = body.append_fmtstr(f\" & self.{i}.eq(other.{i})\");\n }\n f\"{body}\".quoted_contents()\n}\n\nimpl<A: Eq, B: Eq> Eq for (A, B) {\n fn eq(self, other: (A, B)) -> bool {\n make_tuple_eq_body!(2u32)\n }\n}\n\nimpl<A: Eq, B: Eq, C: Eq> Eq for (A, B, C) {\n fn eq(self, other: (A, B, C)) -> bool {\n make_tuple_eq_body!(3u32)\n }\n}\n\nimpl<A: Eq, B: Eq, C: Eq, D: Eq> Eq for (A, B, C, D) {\n fn eq(self, other: (A, B, C, D)) -> bool {\n make_tuple_eq_body!(4u32)\n }\n}\n\nimpl<A: Eq, B: Eq, C: Eq, D: Eq, E: Eq> Eq for (A, B, C, D, E) {\n fn eq(self, other: (A, B, C, D, E)) -> bool {\n make_tuple_eq_body!(5u32)\n }\n}\n\nimpl<A: Eq, B: Eq, C: Eq, D: Eq, E: Eq, F: Eq> Eq for (A, B, C, D, E, F) {\n fn eq(self, other: (A, B, C, D, E, F)) -> bool {\n make_tuple_eq_body!(6u32)\n }\n}\n\nimpl<A: Eq, B: Eq, C: Eq, D: Eq, E: Eq, F: Eq, G: Eq> Eq for (A, B, C, D, E, F, G) {\n fn eq(self, other: (A, B, C, D, E, F, G)) -> bool {\n make_tuple_eq_body!(7u32)\n }\n}\n\nimpl<A: Eq, B: Eq, C: Eq, D: Eq, E: Eq, F: Eq, G: Eq, H: Eq> Eq for (A, B, C, D, E, F, G, H) {\n fn eq(self, other: (A, B, C, D, E, F, G, H)) -> bool {\n make_tuple_eq_body!(8u32)\n }\n}\n\nimpl<A: Eq, B: Eq, C: Eq, D: Eq, E: Eq, F: Eq, G: Eq, H: Eq, I: Eq> Eq for (A, B, C, D, E, F, G, H, I) {\n fn eq(self, other: (A, B, C, D, E, F, G, H, I)) -> bool {\n make_tuple_eq_body!(9u32)\n }\n}\n\nimpl<A: Eq, B: Eq, C: Eq, D: Eq, E: Eq, F: Eq, G: Eq, H: Eq, I: Eq, J: Eq> Eq for (A, B, C, D, E, F, G, H, I, J) {\n fn eq(self, other: (A, B, C, D, E, F, G, H, I, J)) -> bool {\n make_tuple_eq_body!(10u32)\n }\n}\n\nimpl<A: Eq, B: Eq, C: Eq, D: Eq, E: Eq, F: Eq, G: Eq, H: Eq, I: Eq, J: Eq, K: Eq> Eq for (A, B, C, D, E, F, G, H, I, J, K) {\n fn eq(self, other: (A, B, C, D, E, F, G, H, I, J, K)) -> bool {\n make_tuple_eq_body!(11u32)\n }\n}\n\nimpl<A: Eq, B: Eq, C: Eq, D: Eq, E: Eq, F: Eq, G: Eq, H: Eq, I: Eq, J: Eq, K: Eq, L: Eq> Eq for (A, B, C, D, E, F, G, H, I, J, K, L) {\n fn eq(self, other: (A, B, C, D, E, F, G, H, I, J, K, L)) -> bool {\n make_tuple_eq_body!(12u32)\n }\n}\n\nimpl Eq for Ordering {\n fn eq(self, other: Ordering) -> bool {\n self.result == other.result\n }\n}\n\n// Noir doesn't have enums yet so we emulate (Lt | Eq | Gt) with a struct\n// that has 3 public functions for constructing the struct.\n/// A value with three states: `Ordering::less()`, `Ordering::equal()` or `Ordering::greater()`.\n/// Most often used to encode the result of a comparison operation.\npub struct Ordering {\n result: Field,\n}\n\nimpl Ordering {\n // Implementation note: 0, 1, and 2 for Lt, Eq, and Gt are built\n // into the compiler, do not change these without also updating\n // the compiler itself!\n pub fn less() -> Ordering {\n Ordering { result: 0 }\n }\n\n pub fn equal() -> Ordering {\n Ordering { result: 1 }\n }\n\n pub fn greater() -> Ordering {\n Ordering { result: 2 }\n }\n}\n\n/// Compare one object to another, returning whether it is less-than, equal-to,\n/// or greater-than the other object.\n#[derive_via(derive_ord)]\n// docs:start:ord-trait\npub trait Ord {\n fn cmp(self, other: Self) -> Ordering;\n}\n// docs:end:ord-trait\n\n// docs:start:derive_ord\ncomptime fn derive_ord(s: TypeDefinition) -> Quoted {\n let name = quote { $crate::cmp::Ord };\n let signature = quote { fn cmp(_self: Self, _other: Self) -> $crate::cmp::Ordering };\n let for_each_field = |name| quote {\n if result == $crate::cmp::Ordering::equal() {\n result = _self.$name.cmp(_other.$name);\n }\n };\n let body = |fields| quote {\n let mut result = $crate::cmp::Ordering::equal();\n $fields\n result\n };\n crate::meta::make_trait_impl(s, name, signature, for_each_field, quote {}, body)\n}\n// docs:end:derive_ord\n\n// Note: Field deliberately does not implement Ord\n\nimpl Ord for u128 {\n fn cmp(self, other: u128) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\nimpl Ord for u64 {\n fn cmp(self, other: u64) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl Ord for u32 {\n fn cmp(self, other: u32) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl Ord for u16 {\n fn cmp(self, other: u16) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl Ord for u8 {\n fn cmp(self, other: u8) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl Ord for i8 {\n fn cmp(self, other: i8) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl Ord for i16 {\n fn cmp(self, other: i16) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl Ord for i32 {\n fn cmp(self, other: i32) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl Ord for i64 {\n fn cmp(self, other: i64) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl Ord for () {\n fn cmp(_self: Self, _other: ()) -> Ordering {\n Ordering::equal()\n }\n}\n\nimpl Ord for bool {\n fn cmp(self, other: bool) -> Ordering {\n if self {\n if other {\n Ordering::equal()\n } else {\n Ordering::greater()\n }\n } else if other {\n Ordering::less()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl<T, let N: u32> Ord for [T; N]\nwhere\n T: Ord,\n{\n // The first non-equal element of both arrays determines\n // the ordering for the whole array.\n fn cmp(self, other: [T; N]) -> Ordering {\n let mut result = Ordering::equal();\n for i in 0..self.len() {\n if result == Ordering::equal() {\n result = self[i].cmp(other[i]);\n }\n }\n result\n }\n}\n\nimpl<T> Ord for [T]\nwhere\n T: Ord,\n{\n // The first non-equal element of both arrays determines\n // the ordering for the whole array.\n fn cmp(self, other: [T]) -> Ordering {\n let self_len = self.len();\n let other_len = other.len();\n let min_len = if self_len < other_len {\n self_len\n } else {\n other_len\n };\n\n let mut result = Ordering::equal();\n for i in 0..min_len {\n if result == Ordering::equal() {\n result = self[i].cmp(other[i]);\n }\n }\n\n if result != Ordering::equal() {\n result\n } else {\n self_len.cmp(other_len)\n }\n }\n}\n\ncomptime fn make_tuple_ord_body(n: u32) -> Quoted {\n let last = n - 1u32;\n let mut body = if last == 1 {\n f\"let result = self.0.cmp(other.0);\".as_ctstring()\n } else {\n f\"let mut result = self.0.cmp(other.0);\".as_ctstring()\n };\n for i in 1u32..last {\n body = body.append_fmtstr(\n f\" if result == Ordering::equal() {{ result = self.{i}.cmp(other.{i}); }}\",\n );\n }\n body = body.append_fmtstr(\n f\" if result != Ordering::equal() {{ result }} else {{ self.{last}.cmp(other.{last}) }}\",\n );\n f\"{body}\".quoted_contents()\n}\n\nimpl<A: Ord, B: Ord> Ord for (A, B) {\n fn cmp(self, other: (A, B)) -> Ordering {\n make_tuple_ord_body!(2u32)\n }\n}\n\nimpl<A: Ord, B: Ord, C: Ord> Ord for (A, B, C) {\n fn cmp(self, other: (A, B, C)) -> Ordering {\n make_tuple_ord_body!(3u32)\n }\n}\n\nimpl<A: Ord, B: Ord, C: Ord, D: Ord> Ord for (A, B, C, D) {\n fn cmp(self, other: (A, B, C, D)) -> Ordering {\n make_tuple_ord_body!(4u32)\n }\n}\n\nimpl<A: Ord, B: Ord, C: Ord, D: Ord, E: Ord> Ord for (A, B, C, D, E) {\n fn cmp(self, other: (A, B, C, D, E)) -> Ordering {\n make_tuple_ord_body!(5u32)\n }\n}\n\nimpl<A: Ord, B: Ord, C: Ord, D: Ord, E: Ord, F: Ord> Ord for (A, B, C, D, E, F) {\n fn cmp(self, other: (A, B, C, D, E, F)) -> Ordering {\n make_tuple_ord_body!(6u32)\n }\n}\n\nimpl<A: Ord, B: Ord, C: Ord, D: Ord, E: Ord, F: Ord, G: Ord> Ord for (A, B, C, D, E, F, G) {\n fn cmp(self, other: (A, B, C, D, E, F, G)) -> Ordering {\n make_tuple_ord_body!(7u32)\n }\n}\n\nimpl<A: Ord, B: Ord, C: Ord, D: Ord, E: Ord, F: Ord, G: Ord, H: Ord> Ord for (A, B, C, D, E, F, G, H) {\n fn cmp(self, other: (A, B, C, D, E, F, G, H)) -> Ordering {\n make_tuple_ord_body!(8u32)\n }\n}\n\nimpl<A: Ord, B: Ord, C: Ord, D: Ord, E: Ord, F: Ord, G: Ord, H: Ord, I: Ord> Ord for (A, B, C, D, E, F, G, H, I) {\n fn cmp(self, other: (A, B, C, D, E, F, G, H, I)) -> Ordering {\n make_tuple_ord_body!(9u32)\n }\n}\n\nimpl<A: Ord, B: Ord, C: Ord, D: Ord, E: Ord, F: Ord, G: Ord, H: Ord, I: Ord, J: Ord> Ord for (A, B, C, D, E, F, G, H, I, J) {\n fn cmp(self, other: (A, B, C, D, E, F, G, H, I, J)) -> Ordering {\n make_tuple_ord_body!(10u32)\n }\n}\n\nimpl<A: Ord, B: Ord, C: Ord, D: Ord, E: Ord, F: Ord, G: Ord, H: Ord, I: Ord, J: Ord, K: Ord> Ord for (A, B, C, D, E, F, G, H, I, J, K) {\n fn cmp(self, other: (A, B, C, D, E, F, G, H, I, J, K)) -> Ordering {\n make_tuple_ord_body!(11u32)\n }\n}\n\nimpl<A: Ord, B: Ord, C: Ord, D: Ord, E: Ord, F: Ord, G: Ord, H: Ord, I: Ord, J: Ord, K: Ord, L: Ord> Ord for (A, B, C, D, E, F, G, H, I, J, K, L) {\n fn cmp(self, other: (A, B, C, D, E, F, G, H, I, J, K, L)) -> Ordering {\n make_tuple_ord_body!(12u32)\n }\n}\n\n/// Compares and returns the maximum of two values.\n///\n/// Returns the second argument if the comparison determines them to be equal.\n///\n/// # Examples\n///\n/// ```\n/// use std::cmp;\n///\n/// assert_eq(cmp::max(1, 2), 2);\n/// assert_eq(cmp::max(2, 2), 2);\n/// ```\npub fn max<T>(v1: T, v2: T) -> T\nwhere\n T: Ord,\n{\n if v1 > v2 {\n v1\n } else {\n v2\n }\n}\n\n/// Compares and returns the minimum of two values.\n///\n/// Returns the first argument if the comparison determines them to be equal.\n///\n/// # Examples\n///\n/// ```\n/// use std::cmp;\n///\n/// assert_eq(cmp::min(1, 2), 1);\n/// assert_eq(cmp::min(2, 2), 2);\n/// ```\npub fn min<T>(v1: T, v2: T) -> T\nwhere\n T: Ord,\n{\n if v1 > v2 {\n v2\n } else {\n v1\n }\n}\n\nmod cmp_tests {\n use super::{Eq, max, min, Ord};\n\n #[test]\n fn sanity_check_min() {\n assert_eq(min(0_u64, 1), 0);\n assert_eq(min(0_u64, 0), 0);\n assert_eq(min(1_u64, 1), 1);\n assert_eq(min(255_u8, 0), 0);\n }\n\n #[test]\n fn sanity_check_max() {\n assert_eq(max(0_u64, 1), 1);\n assert_eq(max(0_u64, 0), 0);\n assert_eq(max(1_u64, 1), 1);\n assert_eq(max(255_u8, 0), 255);\n }\n\n #[test]\n fn correctly_handles_unequal_length_vectors() {\n let vector_1 = [0, 1, 2, 3].as_vector();\n let vector_2 = [0, 1, 2].as_vector();\n assert(!vector_1.eq(vector_2));\n }\n\n #[test]\n fn lexicographic_ordering_for_vectors() {\n assert(\n [2_u32].as_vector().cmp([1_u32, 1_u32, 1_u32].as_vector())\n == super::Ordering::greater(),\n );\n assert(\n [1_u32, 2_u32].as_vector().cmp([1_u32, 2_u32, 3_u32].as_vector())\n == super::Ordering::less(),\n );\n }\n}\n"
6440
+ "source": "use crate::meta::ctstring::AsCtString;\nuse crate::meta::derive_via;\n\n/// Compare two values for equality\n#[derive_via(derive_eq)]\n// docs:start:eq-trait\npub trait Eq {\n fn eq(self, other: Self) -> bool;\n}\n// docs:end:eq-trait\n\n// docs:start:derive_eq\ncomptime fn derive_eq(s: TypeDefinition) -> Quoted {\n let signature = quote { fn eq(_self: Self, _other: Self) -> bool };\n let for_each_field = |name| quote { (_self.$name == _other.$name) };\n let body = |fields| {\n if s.fields_as_written().len() == 0 {\n quote { true }\n } else {\n fields\n }\n };\n crate::meta::make_trait_impl(\n s,\n quote { $crate::cmp::Eq },\n signature,\n for_each_field,\n quote { & },\n body,\n )\n}\n// docs:end:derive_eq\n\nimpl Eq for Field {\n fn eq(self, other: Field) -> bool {\n self == other\n }\n}\n\nimpl Eq for u128 {\n fn eq(self, other: u128) -> bool {\n self == other\n }\n}\nimpl Eq for u64 {\n fn eq(self, other: u64) -> bool {\n self == other\n }\n}\nimpl Eq for u32 {\n fn eq(self, other: u32) -> bool {\n self == other\n }\n}\nimpl Eq for u16 {\n fn eq(self, other: u16) -> bool {\n self == other\n }\n}\nimpl Eq for u8 {\n fn eq(self, other: u8) -> bool {\n self == other\n }\n}\nimpl Eq for i8 {\n fn eq(self, other: i8) -> bool {\n self == other\n }\n}\nimpl Eq for i16 {\n fn eq(self, other: i16) -> bool {\n self == other\n }\n}\nimpl Eq for i32 {\n fn eq(self, other: i32) -> bool {\n self == other\n }\n}\nimpl Eq for i64 {\n fn eq(self, other: i64) -> bool {\n self == other\n }\n}\n\nimpl Eq for () {\n fn eq(_self: Self, _other: ()) -> bool {\n true\n }\n}\nimpl Eq for bool {\n fn eq(self, other: bool) -> bool {\n self == other\n }\n}\n\nimpl<T, let N: u32> Eq for [T; N]\nwhere\n T: Eq,\n{\n fn eq(self, other: [T; N]) -> bool {\n let mut result = true;\n for i in 0..self.len() {\n result &= self[i].eq(other[i]);\n }\n result\n }\n}\n\nimpl<T> Eq for [T]\nwhere\n T: Eq,\n{\n fn eq(self, other: [T]) -> bool {\n let mut result = self.len() == other.len();\n if result {\n for i in 0..self.len() {\n result &= self[i].eq(other[i]);\n }\n }\n result\n }\n}\n\nimpl<let N: u32> Eq for str<N> {\n fn eq(self, other: str<N>) -> bool {\n let self_bytes = self.as_bytes();\n let other_bytes = other.as_bytes();\n self_bytes == other_bytes\n }\n}\n\ncomptime fn make_tuple_eq_body(n: u32) -> Quoted {\n let mut body = f\"self.0.eq(other.0)\".as_ctstring();\n for i in 1u32..n {\n body = body.append_fmtstr(f\" & self.{i}.eq(other.{i})\");\n }\n f\"{body}\".quoted_contents()\n}\n\nimpl<A: Eq, B: Eq> Eq for (A, B) {\n fn eq(self, other: (A, B)) -> bool {\n make_tuple_eq_body!(2u32)\n }\n}\n\nimpl<A: Eq, B: Eq, C: Eq> Eq for (A, B, C) {\n fn eq(self, other: (A, B, C)) -> bool {\n make_tuple_eq_body!(3u32)\n }\n}\n\nimpl<A: Eq, B: Eq, C: Eq, D: Eq> Eq for (A, B, C, D) {\n fn eq(self, other: (A, B, C, D)) -> bool {\n make_tuple_eq_body!(4u32)\n }\n}\n\nimpl<A: Eq, B: Eq, C: Eq, D: Eq, E: Eq> Eq for (A, B, C, D, E) {\n fn eq(self, other: (A, B, C, D, E)) -> bool {\n make_tuple_eq_body!(5u32)\n }\n}\n\nimpl<A: Eq, B: Eq, C: Eq, D: Eq, E: Eq, F: Eq> Eq for (A, B, C, D, E, F) {\n fn eq(self, other: (A, B, C, D, E, F)) -> bool {\n make_tuple_eq_body!(6u32)\n }\n}\n\nimpl<A: Eq, B: Eq, C: Eq, D: Eq, E: Eq, F: Eq, G: Eq> Eq for (A, B, C, D, E, F, G) {\n fn eq(self, other: (A, B, C, D, E, F, G)) -> bool {\n make_tuple_eq_body!(7u32)\n }\n}\n\nimpl<A: Eq, B: Eq, C: Eq, D: Eq, E: Eq, F: Eq, G: Eq, H: Eq> Eq for (A, B, C, D, E, F, G, H) {\n fn eq(self, other: (A, B, C, D, E, F, G, H)) -> bool {\n make_tuple_eq_body!(8u32)\n }\n}\n\nimpl<A: Eq, B: Eq, C: Eq, D: Eq, E: Eq, F: Eq, G: Eq, H: Eq, I: Eq> Eq for (A, B, C, D, E, F, G, H, I) {\n fn eq(self, other: (A, B, C, D, E, F, G, H, I)) -> bool {\n make_tuple_eq_body!(9u32)\n }\n}\n\nimpl<A: Eq, B: Eq, C: Eq, D: Eq, E: Eq, F: Eq, G: Eq, H: Eq, I: Eq, J: Eq> Eq for (A, B, C, D, E, F, G, H, I, J) {\n fn eq(self, other: (A, B, C, D, E, F, G, H, I, J)) -> bool {\n make_tuple_eq_body!(10u32)\n }\n}\n\nimpl<A: Eq, B: Eq, C: Eq, D: Eq, E: Eq, F: Eq, G: Eq, H: Eq, I: Eq, J: Eq, K: Eq> Eq for (A, B, C, D, E, F, G, H, I, J, K) {\n fn eq(self, other: (A, B, C, D, E, F, G, H, I, J, K)) -> bool {\n make_tuple_eq_body!(11u32)\n }\n}\n\nimpl<A: Eq, B: Eq, C: Eq, D: Eq, E: Eq, F: Eq, G: Eq, H: Eq, I: Eq, J: Eq, K: Eq, L: Eq> Eq for (A, B, C, D, E, F, G, H, I, J, K, L) {\n fn eq(self, other: (A, B, C, D, E, F, G, H, I, J, K, L)) -> bool {\n make_tuple_eq_body!(12u32)\n }\n}\n\nimpl Eq for Ordering {\n fn eq(self, other: Ordering) -> bool {\n self.result == other.result\n }\n}\n\n// Noir doesn't have enums yet so we emulate (Lt | Eq | Gt) with a struct\n// that has 3 public functions for constructing the struct.\n/// A value with three states: `Ordering::less()`, `Ordering::equal()` or `Ordering::greater()`.\n/// Most often used to encode the result of a comparison operation.\npub struct Ordering {\n result: Field,\n}\n\nimpl Ordering {\n // Implementation note: 0, 1, and 2 for Lt, Eq, and Gt are built\n // into the compiler, do not change these without also updating\n // the compiler itself!\n pub fn less() -> Ordering {\n Ordering { result: 0 }\n }\n\n pub fn equal() -> Ordering {\n Ordering { result: 1 }\n }\n\n pub fn greater() -> Ordering {\n Ordering { result: 2 }\n }\n}\n\n/// Compare one object to another, returning whether it is less-than, equal-to,\n/// or greater-than the other object.\n#[derive_via(derive_ord)]\n// docs:start:ord-trait\npub trait Ord {\n fn cmp(self, other: Self) -> Ordering;\n}\n// docs:end:ord-trait\n\n// docs:start:derive_ord\ncomptime fn derive_ord(s: TypeDefinition) -> Quoted {\n let name = quote { $crate::cmp::Ord };\n let signature = quote { fn cmp(_self: Self, _other: Self) -> $crate::cmp::Ordering };\n let for_each_field = |name| quote {\n if result == $crate::cmp::Ordering::equal() {\n result = _self.$name.cmp(_other.$name);\n }\n };\n let body = |fields| quote {\n let mut result = $crate::cmp::Ordering::equal();\n $fields\n result\n };\n crate::meta::make_trait_impl(s, name, signature, for_each_field, quote {}, body)\n}\n// docs:end:derive_ord\n\n// Note: Field deliberately does not implement Ord\n\nimpl Ord for u128 {\n fn cmp(self, other: u128) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\nimpl Ord for u64 {\n fn cmp(self, other: u64) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl Ord for u32 {\n fn cmp(self, other: u32) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl Ord for u16 {\n fn cmp(self, other: u16) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl Ord for u8 {\n fn cmp(self, other: u8) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl Ord for i8 {\n fn cmp(self, other: i8) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl Ord for i16 {\n fn cmp(self, other: i16) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl Ord for i32 {\n fn cmp(self, other: i32) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl Ord for i64 {\n fn cmp(self, other: i64) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl Ord for () {\n fn cmp(_self: Self, _other: ()) -> Ordering {\n Ordering::equal()\n }\n}\n\nimpl Ord for bool {\n fn cmp(self, other: bool) -> Ordering {\n if self {\n if other {\n Ordering::equal()\n } else {\n Ordering::greater()\n }\n } else if other {\n Ordering::less()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl<T, let N: u32> Ord for [T; N]\nwhere\n T: Ord,\n{\n // The first non-equal element of both arrays determines\n // the ordering for the whole array.\n fn cmp(self, other: [T; N]) -> Ordering {\n let mut result = Ordering::equal();\n for i in 0..self.len() {\n if result == Ordering::equal() {\n result = self[i].cmp(other[i]);\n }\n }\n result\n }\n}\n\nimpl<T> Ord for [T]\nwhere\n T: Ord,\n{\n // The first non-equal element of both arrays determines\n // the ordering for the whole array.\n fn cmp(self, other: [T]) -> Ordering {\n let self_len = self.len();\n let other_len = other.len();\n let min_len = if self_len < other_len {\n self_len\n } else {\n other_len\n };\n\n let mut result = Ordering::equal();\n for i in 0..min_len {\n if result == Ordering::equal() {\n result = self[i].cmp(other[i]);\n }\n }\n\n if result != Ordering::equal() {\n result\n } else {\n self_len.cmp(other_len)\n }\n }\n}\n\ncomptime fn make_tuple_ord_body(n: u32) -> Quoted {\n let last = n - 1u32;\n let mut body = if last == 1 {\n f\"let result = self.0.cmp(other.0);\".as_ctstring()\n } else {\n f\"let mut result = self.0.cmp(other.0);\".as_ctstring()\n };\n for i in 1u32..last {\n body = body.append_fmtstr(\n f\" if result == Ordering::equal() {{ result = self.{i}.cmp(other.{i}); }}\",\n );\n }\n body = body.append_fmtstr(\n f\" if result != Ordering::equal() {{ result }} else {{ self.{last}.cmp(other.{last}) }}\",\n );\n f\"{body}\".quoted_contents()\n}\n\nimpl<A: Ord, B: Ord> Ord for (A, B) {\n fn cmp(self, other: (A, B)) -> Ordering {\n make_tuple_ord_body!(2u32)\n }\n}\n\nimpl<A: Ord, B: Ord, C: Ord> Ord for (A, B, C) {\n fn cmp(self, other: (A, B, C)) -> Ordering {\n make_tuple_ord_body!(3u32)\n }\n}\n\nimpl<A: Ord, B: Ord, C: Ord, D: Ord> Ord for (A, B, C, D) {\n fn cmp(self, other: (A, B, C, D)) -> Ordering {\n make_tuple_ord_body!(4u32)\n }\n}\n\nimpl<A: Ord, B: Ord, C: Ord, D: Ord, E: Ord> Ord for (A, B, C, D, E) {\n fn cmp(self, other: (A, B, C, D, E)) -> Ordering {\n make_tuple_ord_body!(5u32)\n }\n}\n\nimpl<A: Ord, B: Ord, C: Ord, D: Ord, E: Ord, F: Ord> Ord for (A, B, C, D, E, F) {\n fn cmp(self, other: (A, B, C, D, E, F)) -> Ordering {\n make_tuple_ord_body!(6u32)\n }\n}\n\nimpl<A: Ord, B: Ord, C: Ord, D: Ord, E: Ord, F: Ord, G: Ord> Ord for (A, B, C, D, E, F, G) {\n fn cmp(self, other: (A, B, C, D, E, F, G)) -> Ordering {\n make_tuple_ord_body!(7u32)\n }\n}\n\nimpl<A: Ord, B: Ord, C: Ord, D: Ord, E: Ord, F: Ord, G: Ord, H: Ord> Ord for (A, B, C, D, E, F, G, H) {\n fn cmp(self, other: (A, B, C, D, E, F, G, H)) -> Ordering {\n make_tuple_ord_body!(8u32)\n }\n}\n\nimpl<A: Ord, B: Ord, C: Ord, D: Ord, E: Ord, F: Ord, G: Ord, H: Ord, I: Ord> Ord for (A, B, C, D, E, F, G, H, I) {\n fn cmp(self, other: (A, B, C, D, E, F, G, H, I)) -> Ordering {\n make_tuple_ord_body!(9u32)\n }\n}\n\nimpl<A: Ord, B: Ord, C: Ord, D: Ord, E: Ord, F: Ord, G: Ord, H: Ord, I: Ord, J: Ord> Ord for (A, B, C, D, E, F, G, H, I, J) {\n fn cmp(self, other: (A, B, C, D, E, F, G, H, I, J)) -> Ordering {\n make_tuple_ord_body!(10u32)\n }\n}\n\nimpl<A: Ord, B: Ord, C: Ord, D: Ord, E: Ord, F: Ord, G: Ord, H: Ord, I: Ord, J: Ord, K: Ord> Ord for (A, B, C, D, E, F, G, H, I, J, K) {\n fn cmp(self, other: (A, B, C, D, E, F, G, H, I, J, K)) -> Ordering {\n make_tuple_ord_body!(11u32)\n }\n}\n\nimpl<A: Ord, B: Ord, C: Ord, D: Ord, E: Ord, F: Ord, G: Ord, H: Ord, I: Ord, J: Ord, K: Ord, L: Ord> Ord for (A, B, C, D, E, F, G, H, I, J, K, L) {\n fn cmp(self, other: (A, B, C, D, E, F, G, H, I, J, K, L)) -> Ordering {\n make_tuple_ord_body!(12u32)\n }\n}\n\n/// Compares and returns the maximum of two values.\n///\n/// Returns the second argument if the comparison determines them to be equal.\n///\n/// # Examples\n///\n/// ```\n/// use std::cmp;\n///\n/// assert_eq(cmp::max(1, 2), 2);\n/// assert_eq(cmp::max(2, 2), 2);\n/// ```\npub fn max<T>(v1: T, v2: T) -> T\nwhere\n T: Ord,\n{\n if v1 > v2 {\n v1\n } else {\n v2\n }\n}\n\n/// Compares and returns the minimum of two values.\n///\n/// Returns the first argument if the comparison determines them to be equal.\n///\n/// # Examples\n///\n/// ```\n/// use std::cmp;\n///\n/// assert_eq(cmp::min(1, 2), 1);\n/// assert_eq(cmp::min(2, 2), 2);\n/// ```\npub fn min<T>(v1: T, v2: T) -> T\nwhere\n T: Ord,\n{\n if v1 > v2 {\n v2\n } else {\n v1\n }\n}\n\nmod cmp_tests {\n use super::{Eq, max, min, Ord};\n\n #[test]\n fn sanity_check_min() {\n assert_eq(min(0_u64, 1), 0);\n assert_eq(min(0_u64, 0), 0);\n assert_eq(min(1_u64, 1), 1);\n assert_eq(min(255_u8, 0), 0);\n }\n\n #[test]\n fn sanity_check_max() {\n assert_eq(max(0_u64, 1), 1);\n assert_eq(max(0_u64, 0), 0);\n assert_eq(max(1_u64, 1), 1);\n assert_eq(max(255_u8, 0), 255);\n }\n\n #[test]\n fn correctly_handles_unequal_length_vectors() {\n let vector_1 = [0, 1, 2, 3].as_vector();\n let vector_2 = [0, 1, 2].as_vector();\n assert(!vector_1.eq(vector_2));\n }\n\n #[test]\n fn lexicographic_ordering_for_vectors() {\n assert(\n [2_u32].as_vector().cmp([1_u32, 1_u32, 1_u32].as_vector())\n == super::Ordering::greater(),\n );\n assert(\n [1_u32, 2_u32].as_vector().cmp([1_u32, 2_u32, 3_u32].as_vector())\n == super::Ordering::less(),\n );\n }\n}\n"
6469
6441
  },
6470
6442
  "50": {
6471
6443
  "function_locations": [
@@ -7217,115 +7189,115 @@
7217
7189
  },
7218
7190
  {
7219
7191
  "name": "PublicContext::l1_to_l2_msg_exists",
7220
- "start": 6809
7192
+ "start": 6824
7221
7193
  },
7222
7194
  {
7223
7195
  "name": "PublicContext::nullifier_exists_unsafe",
7224
- "start": 10009
7196
+ "start": 10039
7225
7197
  },
7226
7198
  {
7227
7199
  "name": "PublicContext::consume_l1_to_l2_message",
7228
- "start": 11859
7200
+ "start": 11904
7229
7201
  },
7230
7202
  {
7231
7203
  "name": "PublicContext::message_portal",
7232
- "start": 13976
7204
+ "start": 14021
7233
7205
  },
7234
7206
  {
7235
7207
  "name": "PublicContext::call_public_function",
7236
- "start": 14866
7208
+ "start": 14911
7237
7209
  },
7238
7210
  {
7239
7211
  "name": "PublicContext::static_call_public_function",
7240
- "start": 16498
7212
+ "start": 16543
7241
7213
  },
7242
7214
  {
7243
7215
  "name": "PublicContext::push_note_hash",
7244
- "start": 18282
7216
+ "start": 18327
7245
7217
  },
7246
7218
  {
7247
7219
  "name": "PublicContext::push_nullifier",
7248
- "start": 19721
7220
+ "start": 19766
7249
7221
  },
7250
7222
  {
7251
7223
  "name": "PublicContext::this_address",
7252
- "start": 20311
7224
+ "start": 20356
7253
7225
  },
7254
7226
  {
7255
7227
  "name": "PublicContext::maybe_msg_sender",
7256
- "start": 21406
7228
+ "start": 21451
7257
7229
  },
7258
7230
  {
7259
7231
  "name": "PublicContext::selector",
7260
- "start": 22178
7232
+ "start": 22223
7261
7233
  },
7262
7234
  {
7263
7235
  "name": "PublicContext::get_args_hash",
7264
- "start": 22917
7236
+ "start": 22962
7265
7237
  },
7266
7238
  {
7267
7239
  "name": "PublicContext::transaction_fee",
7268
- "start": 24309
7240
+ "start": 24354
7269
7241
  },
7270
7242
  {
7271
7243
  "name": "PublicContext::chain_id",
7272
- "start": 24898
7244
+ "start": 24943
7273
7245
  },
7274
7246
  {
7275
7247
  "name": "PublicContext::version",
7276
- "start": 25568
7248
+ "start": 25613
7277
7249
  },
7278
7250
  {
7279
7251
  "name": "PublicContext::block_number",
7280
- "start": 26508
7252
+ "start": 26553
7281
7253
  },
7282
7254
  {
7283
7255
  "name": "PublicContext::timestamp",
7284
- "start": 27620
7256
+ "start": 27665
7285
7257
  },
7286
7258
  {
7287
7259
  "name": "PublicContext::min_fee_per_l2_gas",
7288
- "start": 28901
7260
+ "start": 28946
7289
7261
  },
7290
7262
  {
7291
7263
  "name": "PublicContext::min_fee_per_da_gas",
7292
- "start": 29428
7264
+ "start": 29473
7293
7265
  },
7294
7266
  {
7295
7267
  "name": "PublicContext::l2_gas_left",
7296
- "start": 29826
7268
+ "start": 29871
7297
7269
  },
7298
7270
  {
7299
7271
  "name": "PublicContext::da_gas_left",
7300
- "start": 30442
7272
+ "start": 30487
7301
7273
  },
7302
7274
  {
7303
7275
  "name": "PublicContext::is_static_call",
7304
- "start": 30907
7276
+ "start": 30952
7305
7277
  },
7306
7278
  {
7307
7279
  "name": "PublicContext::raw_storage_read",
7308
- "start": 31734
7280
+ "start": 31794
7309
7281
  },
7310
7282
  {
7311
7283
  "name": "PublicContext::storage_read",
7312
- "start": 32592
7284
+ "start": 32652
7313
7285
  },
7314
7286
  {
7315
7287
  "name": "PublicContext::raw_storage_write",
7316
- "start": 33260
7288
+ "start": 33320
7317
7289
  },
7318
7290
  {
7319
7291
  "name": "PublicContext::storage_write",
7320
- "start": 33994
7292
+ "start": 34054
7321
7293
  },
7322
7294
  {
7323
7295
  "name": "<impl Empty for PublicContext>::empty",
7324
- "start": 34119
7296
+ "start": 34179
7325
7297
  }
7326
7298
  ],
7327
7299
  "path": "/home/aztec-dev/aztec-packages/noir-projects/aztec-nr/aztec/src/context/public_context.nr",
7328
- "source": "use crate::{\n context::gas::GasOpts,\n hash::{\n compute_l1_to_l2_message_hash, compute_l1_to_l2_message_nullifier, compute_secret_hash,\n compute_siloed_nullifier,\n },\n oracle::avm,\n};\nuse crate::protocol::{\n abis::function_selector::FunctionSelector,\n address::{AztecAddress, EthAddress},\n constants::{MAX_U32_VALUE, NULL_MSG_SENDER_CONTRACT_ADDRESS},\n traits::{Empty, FromField, Packable, Serialize, ToField},\n utils::writer::Writer,\n};\n\n/// # PublicContext\n///\n/// The **main interface** between an #[external(\"public\")] function and the Aztec blockchain.\n///\n/// An instance of the PublicContext is initialized automatically at the outset of every public function, within the\n/// #[external(\"public\")] macro, so you'll never need to consciously instantiate this yourself.\n///\n/// The instance is always named `context`, and it will always be available within the body of every\n/// #[external(\"public\")] function in your smart contract.\n///\n/// Typical usage for a smart contract developer will be to call getter methods of the PublicContext.\n///\n/// _Pushing_ data and requests to the context is mostly handled within aztec-nr's own functions, so typically a smart\n/// contract developer won't need to call any setter methods directly.\n///\n/// ## Responsibilities\n/// - Exposes contextual data to a public function:\n/// - Data relating to how this public function was called:\n/// - msg_sender, this_address\n/// - Data relating to the current blockchain state:\n/// - timestamp, block_number, chain_id, version\n/// - Gas and fee information\n/// - Provides state access:\n/// - Read/write public storage (key-value mapping)\n/// - Check existence of notes and nullifiers (Some patterns use notes & nullifiers to store public (not private)\n/// information)\n/// - Enables consumption of L1->L2 messages.\n/// - Enables calls to other public smart contract functions:\n/// - Writes data to the blockchain:\n/// - Updates to public state variables\n/// - New public logs (for events)\n/// - New L2->L1 messages\n/// - New notes & nullifiers (E.g. pushing public info to notes/nullifiers, or for completing \"partial notes\")\n///\n/// ## Key Differences from Private Execution\n///\n/// Unlike private functions -- which are executed on the user's device and which can only reference historic state --\n/// public functions are executed by a block proposer and are executed \"live\" on the _current_ tip of the chain. This\n/// means public functions can:\n/// - Read and write _current_ public state\n/// - Immediately see the effects of earlier transactions in the same block\n///\n/// Also, public functions are executed within a zkVM (the \"AVM\"), so that they can _revert_ whilst still ensuring\n/// payment to the proposer and prover. (Private functions cannot revert: they either succeed, or they cannot be\n/// included).\n///\n/// ## Optimising Public Functions\n///\n/// Using the AVM to execute public functions means they compile down to \"AVM bytecode\" instead of the ACIR that\n/// private functions (standalone circuits) compile to. Therefore the approach to optimising a public function is\n/// fundamentally different from optimising a public function.\n///\npub struct PublicContext {\n pub args_hash: Option<Field>,\n pub compute_args_hash: fn() -> Field,\n}\n\nimpl Eq for PublicContext {\n fn eq(self, other: Self) -> bool {\n (self.args_hash == other.args_hash)\n // Can't compare the function compute_args_hash\n }\n}\n\nimpl PublicContext {\n /// Creates a new PublicContext instance.\n ///\n /// Low-level function: This is called automatically by the #[external(\"public\")] macro, so you shouldn't need to\n /// be called directly by smart contract developers.\n ///\n /// # Arguments\n /// * `compute_args_hash` - Function to compute the args_hash\n ///\n /// # Returns\n /// * A new PublicContext instance\n ///\n pub fn new(compute_args_hash: fn() -> Field) -> Self {\n PublicContext { args_hash: Option::none(), compute_args_hash }\n }\n\n /// Emits a _public_ log that will be visible onchain to everyone.\n ///\n /// # Arguments\n /// * `tag` - A tag placed at `fields[0]` of the emitted log. Nodes index logs by this value, allowing\n /// clients to efficiently query for matching logs without scanning all of them.\n /// * `log` - The data to log, must implement Serialize trait.\n ///\n /// ## Safety\n ///\n /// The `tag` should be domain-separated (e.g. via [`crate::protocol::hash::compute_log_tag`]) to prevent\n /// collisions between logs from different sources. Without domain separation, two unrelated log types that\n /// happen to share a raw tag value become indistinguishable. Prefer `self.emit(event)` for events, which\n /// handles tagging automatically.\n pub fn emit_public_log_unsafe<T>(_self: Self, tag: Field, log: T)\n where\n T: Serialize,\n {\n // We use a Writer to serialize the log directly after the tag, avoiding an extra O(n) copy that would\n // result from serializing first and then prepending the tag.\n let mut writer: Writer<1 + <T as Serialize>::N> = Writer::new();\n writer.write(tag);\n Serialize::stream_serialize(log, &mut writer);\n // Safety: AVM opcodes are constrained by the AVM itself\n unsafe { avm::emit_public_log(writer.finish().as_vector()) };\n }\n\n /// Checks if a given note hash exists in the note hash tree at a particular leaf_index.\n ///\n /// # Arguments\n /// * `note_hash` - The note hash to check for existence\n /// * `leaf_index` - The index where the note hash should be located\n ///\n /// # Returns\n /// * `bool` - True if the note hash exists at the specified index\n ///\n pub fn note_hash_exists(_self: Self, note_hash: Field, leaf_index: u64) -> bool {\n // Safety: AVM opcodes are constrained by the AVM itself\n unsafe { avm::note_hash_exists(note_hash, leaf_index) } == 1\n }\n\n /// Checks if a specific L1-to-L2 message exists in the L1-to-L2 message tree at a particular leaf index.\n ///\n /// Common use cases include token bridging, cross-chain governance, and triggering L2 actions based on L1 events.\n ///\n /// This function should be called before attempting to consume an L1-to-L2 message.\n ///\n /// # Arguments\n /// * `msg_hash` - Hash of the L1-to-L2 message to check\n /// * `msg_leaf_index` - The index where the message should be located\n ///\n /// # Returns\n /// * `bool` - True if the message exists at the specified index\n ///\n /// # Advanced\n /// * Uses the AVM l1_to_l2_msg_exists opcode for tree lookup\n /// * Messages are copied from L1 Inbox to L2 by block proposers\n ///\n pub fn l1_to_l2_msg_exists(_self: Self, msg_hash: Field, msg_leaf_index: Field) -> bool {\n // Safety: AVM opcodes are constrained by the AVM itself TODO(alvaro): Make l1l2msg leaf index a u64 upstream\n unsafe { avm::l1_to_l2_msg_exists(msg_hash, msg_leaf_index as u64) } == 1\n }\n\n /// Returns `true` if an `unsiloed_nullifier` has been emitted by `contract_address`.\n ///\n /// Note that unsiloed nullifiers are not the actual values stored in the nullifier tree: they are first siloed via\n /// [`crate::hash::compute_siloed_nullifier`] with the emitting contract's address.\n ///\n /// ## Use Cases\n ///\n /// Nullifiers are typically used as a _privacy-preserving_ record of a one-time action, but they can also be used\n /// to efficiently record _public_ one-time actions as well. This is cheaper than using public storage, and has the\n /// added benefit of the nullifier being emittable from a private function.\n ///\n /// An example is to check whether a contract has been published: we emit a nullifier that is deterministic and\n /// which has a _public_ preimage.\n ///\n /// ## Public vs Private\n ///\n /// In general, one should not attempt to prove nullifier non-existence in private, as that will not consider the\n /// possibility of the nullifier having been emitted in any transaction between the anchor block and the inclusion\n /// block. Private functions instead prove existence via\n /// [`crate::context::PrivateContext::assert_nullifier_exists`]\n /// and 'prove' non-existence by _emitting_ the nullifer, which would cause the transaction to fail if the\n /// nullifier existed.\n ///\n /// This is not the case in public functions, which **do** have access to the tip of the blockchain and so can\n /// reliably prove whether a nullifier exists or not.\n ///\n /// ## Safety\n ///\n /// While it is safe to rely on this function's return value to determine if a nullifier exists or not, it is often\n /// **not** safe to infer additional information from that. In particular, it is **unsafe** to infer that the\n /// existence of a nullifier emitted from a private function implies that all other side-effects of said private\n /// execution have been completed, more concretely that any enqueued public calls have been executed.\n ///\n /// For example, if a function in contract `A` privately emits nullifier `X` and then enqueues public function `Y`,\n /// then it is **unsafe** for a contract `B` to infer that `Y` has alredy executed simply because `X` exists.\n ///\n /// This is because **all** private transaction effects are committed _before_ enqueued public functions are run\n /// (in\n /// order to not reveal detailed timing information about the transaction), so it is possible to observe a\n /// nullifier that was emitted alongside the enqueuing of a public call **before** said call has been completed.\n ///\n /// ## Cost\n ///\n /// This emits the `CHECKNULLIFIEREXISTS` opcode, which conceptually performs a merkle inclusion proof on the\n /// nullifier tree (both when the nullifier exists and when it doesn't).\n pub fn nullifier_exists_unsafe(_self: Self, unsiloed_nullifier: Field, contract_address: AztecAddress) -> bool {\n let siloed_nullifier = compute_siloed_nullifier(contract_address, unsiloed_nullifier);\n // Safety: AVM opcodes are constrained by the AVM itself\n unsafe { avm::nullifier_exists(siloed_nullifier) } == 1\n }\n\n /// Consumes a message sent from Ethereum (L1) to Aztec (L2) -- effectively marking it as \"read\".\n ///\n /// Use this function if you only want the message to ever be \"referred to\" once. Once consumed using this method,\n /// the message cannot be consumed again, because a nullifier is emitted. If your use case wants for the message to\n /// be read unlimited times, then you can always read any historic message from the L1-to-L2 messages tree, using\n /// the `l1_to_l2_msg_exists` method. Messages never technically get deleted from that tree.\n ///\n /// The message will first be inserted into an Aztec \"Inbox\" smart contract on L1. It will not be available for\n /// consumption immediately. Messages get copied-over from the L1 Inbox to L2 by the next Proposer in batches. So\n /// you will need to wait until the messages are copied before you can consume them.\n ///\n /// # Arguments\n /// * `content` - The message content that was sent from L1\n /// * `secret` - Secret value used for message privacy (if needed)\n /// * `sender` - Ethereum address that sent the message\n /// * `leaf_index` - Index of the message in the L1-to-L2 message tree\n ///\n /// # Advanced\n /// * Validates message existence in the L1-to-L2 message tree\n /// * Prevents double-consumption by emitting a nullifier\n /// * Message hash is computed from all parameters + chain context\n /// * Will revert if message doesn't exist or was already consumed\n ///\n pub fn consume_l1_to_l2_message(self: Self, content: Field, secret: Field, sender: EthAddress, leaf_index: Field) {\n let secret_hash = compute_secret_hash(secret);\n let message_hash = compute_l1_to_l2_message_hash(\n sender,\n self.chain_id(),\n /*recipient=*/\n self.this_address(),\n self.version(),\n content,\n secret_hash,\n leaf_index,\n );\n let nullifier = compute_l1_to_l2_message_nullifier(message_hash, secret);\n\n assert(!self.nullifier_exists_unsafe(nullifier, self.this_address()), \"L1-to-L2 message is already nullified\");\n assert(self.l1_to_l2_msg_exists(message_hash, leaf_index), \"Tried to consume nonexistent L1-to-L2 message\");\n\n self.push_nullifier(nullifier);\n }\n\n /// Sends an \"L2 -> L1 message\" from this function (Aztec, L2) to a smart contract on Ethereum (L1). L1 contracts\n /// which are designed to send/receive messages to/from Aztec are called \"Portal Contracts\".\n ///\n /// Common use cases include withdrawals, cross-chain asset transfers, and triggering L1 actions based on L2 state\n /// changes.\n ///\n /// The message will be inserted into an Aztec \"Outbox\" contract on L1, when this transaction's block is proposed\n /// to L1. Sending the message will not result in any immediate state changes in the target portal contract. The\n /// message will need to be manually consumed from the Outbox through a separate Ethereum transaction: a user will\n /// need to call a function of the portal contract -- a function specifically designed to make a call to the Outbox\n /// to consume the message. The message will only be available for consumption once the _epoch_ proof has been\n /// submitted. Given that there are multiple Aztec blocks within an epoch, it might take some time for this epoch\n /// proof to be submitted -- especially if the block was near the start of an epoch.\n ///\n /// # Arguments\n /// * `recipient` - Ethereum address that will receive the message\n /// * `content` - Message content (32 bytes as a Field element)\n ///\n pub fn message_portal(_self: Self, recipient: EthAddress, content: Field) {\n // Safety: AVM opcodes are constrained by the AVM itself\n unsafe { avm::send_l2_to_l1_msg(recipient, content) };\n }\n\n /// Calls a public function on another contract.\n ///\n /// Will revert if the called function reverts or runs out of gas.\n ///\n /// # Arguments\n /// * `contract_address` - Address of the contract to call\n /// * `function_selector` - Function to call on the target contract\n /// * `args` - Arguments to pass to the function\n /// * `gas_opts` - An optional allocation of gas to the called function.\n ///\n /// # Returns\n /// * `[Field]` - Return data from the called function\n ///\n pub unconstrained fn call_public_function<let N: u32>(\n _self: Self,\n contract_address: AztecAddress,\n function_selector: FunctionSelector,\n args: [Field; N],\n gas_opts: GasOpts,\n ) -> [Field] {\n let calldata = [function_selector.to_field()].concat(args);\n\n avm::call(\n gas_opts.l2_gas.unwrap_or(MAX_U32_VALUE),\n gas_opts.da_gas.unwrap_or(MAX_U32_VALUE),\n contract_address,\n calldata,\n );\n // Use success_copy to determine whether the call succeeded\n let success = avm::success_copy();\n\n let result_data = avm::returndata_copy(0, avm::returndata_size());\n if !success {\n // Rethrow the revert data.\n avm::revert(result_data);\n }\n result_data\n }\n\n /// Makes a read-only call to a public function on another contract.\n ///\n /// This is similar to Solidity's `staticcall`. The called function cannot modify state or emit events. Any nested\n /// calls are constrained to also be staticcalls.\n ///\n /// Useful for querying data from other contracts safely.\n ///\n /// Will revert if the called function reverts or runs out of gas.\n ///\n /// # Arguments\n /// * `contract_address` - Address of the contract to call\n /// * `function_selector` - Function to call on the target contract\n /// * `args` - Array of arguments to pass to the called function\n /// * `gas_opts` - An optional allocation of gas to the called function.\n ///\n /// # Returns\n /// * `[Field]` - Return data from the called function\n ///\n pub unconstrained fn static_call_public_function<let N: u32>(\n _self: Self,\n contract_address: AztecAddress,\n function_selector: FunctionSelector,\n args: [Field; N],\n gas_opts: GasOpts,\n ) -> [Field] {\n let calldata = [function_selector.to_field()].concat(args);\n\n avm::call_static(\n gas_opts.l2_gas.unwrap_or(MAX_U32_VALUE),\n gas_opts.da_gas.unwrap_or(MAX_U32_VALUE),\n contract_address,\n calldata,\n );\n // Use success_copy to determine whether the call succeeded\n let success = avm::success_copy();\n\n let result_data = avm::returndata_copy(0, avm::returndata_size());\n if !success {\n // Rethrow the revert data.\n avm::revert(result_data);\n }\n result_data\n }\n\n /// Adds a new note hash to the Aztec blockchain's global Note Hash Tree.\n ///\n /// Notes are ordinarily constructed and emitted by _private_ functions, to ensure that both the content of the\n /// note, and the contract that emitted the note, stay private.\n ///\n /// There are however some useful patterns whereby a note needs to contain _public_ data. The ability to push a new\n /// note_hash from a _public_ function means that notes can be injected with public data immediately -- as soon as\n /// the public value is known. The slower alternative would be to submit a follow-up transaction so that a private\n /// function can inject the data. Both are possible on Aztec.\n ///\n /// Search \"Partial Note\" for a very common pattern which enables a note to be \"partially\" populated with some data\n /// in a _private_ function, and then later \"completed\" with some data in a public function.\n ///\n /// # Arguments\n /// * `note_hash` - The hash of the note to add to the tree\n ///\n /// # Advanced\n /// * The note hash will be siloed with the contract address by the protocol\n ///\n pub fn push_note_hash(_self: Self, note_hash: Field) {\n // Safety: AVM opcodes are constrained by the AVM itself\n unsafe { avm::emit_note_hash(note_hash) };\n }\n\n /// Creates a new [nullifier](crate::nullifier).\n ///\n /// While nullifiers are primarily intended as a _privacy-preserving_ record of a one-time action, they can also\n /// be used to efficiently record _public_ one-time actions. This function allows creating nullifiers from public\n /// contract functions, which behave just like those created from private functions.\n ///\n /// ## Safety\n ///\n /// This is a low-level function that must be used with great care to avoid subtle corruption of contract state.\n ///\n /// In particular, callers must ensure all nullifiers created by a contract are properly domain-separated, so that\n /// unrelated components don't interfere with one another (e.g. a transaction nullifier accidentally marking a\n /// variable as initialized). Note nullifiers should only be created via\n /// [`crate::context::PrivateContext::push_nullifier_for_note_hash`].\n ///\n /// ## Advanced\n ///\n /// The raw `nullifier` is not what is inserted into the Aztec state tree: it will be first siloed by contract\n /// address via [`crate::protocol::hash::compute_siloed_nullifier`] in order to prevent accidental or malicious\n /// interference of nullifiers from different contracts.\n pub fn push_nullifier(_self: Self, nullifier: Field) {\n // Safety: AVM opcodes are constrained by the AVM itself\n unsafe { avm::emit_nullifier(nullifier) };\n }\n\n /// Returns the address of the current contract being executed.\n ///\n /// This is equivalent to `address(this)` in Solidity (hence the name). Use this to identify the current contract's\n /// address, commonly needed for access control or when interacting with other contracts.\n ///\n /// # Returns\n /// * `AztecAddress` - The contract address of the current function being executed.\n ///\n pub fn this_address(_self: Self) -> AztecAddress {\n // Safety: AVM opcodes are constrained by the AVM itself\n unsafe {\n avm::address()\n }\n }\n\n /// Returns the contract address that initiated this function call.\n ///\n /// This is similar to `msg.sender` in Solidity (hence the name).\n ///\n /// Important Note: If the calling function is a _private_ function, then it had the option of hiding its address\n /// when enqueuing this public function call. In such cases, this method will return `Option<AztecAddress>::none`.\n /// If the calling function is a _public_ function, it will always return an `Option<AztecAddress>::some` (i.e. a\n /// non-null value).\n ///\n /// # Returns\n /// * `Option<AztecAddress>` - The address of the smart contract that called this function (be it an app contract\n /// or a user's account contract).\n ///\n /// # Advanced\n /// * Value is provided by the AVM sender opcode\n /// * In nested calls, this is the immediate caller, not the original transaction sender\n ///\n pub fn maybe_msg_sender(_self: Self) -> Option<AztecAddress> {\n // Safety: AVM opcodes are constrained by the AVM itself\n let maybe_msg_sender = unsafe { avm::sender() };\n if maybe_msg_sender == NULL_MSG_SENDER_CONTRACT_ADDRESS {\n Option::none()\n } else {\n Option::some(maybe_msg_sender)\n }\n }\n\n /// Returns the function selector of the currently-executing function.\n ///\n /// This is similar to `msg.sig` in Solidity, returning the first 4 bytes of the function signature.\n ///\n /// # Returns\n /// * `FunctionSelector` - The 4-byte function identifier\n ///\n /// # Advanced\n /// * Extracted from the first element of calldata\n /// * Used internally for function dispatch in the AVM\n ///\n pub fn selector(_self: Self) -> FunctionSelector {\n // The selector is the first element of the calldata when calling a public function through dispatch.\n // Safety: AVM opcodes are constrained by the AVM itself.\n let raw_selector: [Field; 1] = unsafe { avm::calldata_copy(0, 1) };\n FunctionSelector::from_field(raw_selector[0])\n }\n\n /// Returns the hash of the arguments passed to the current function.\n ///\n /// Very low-level function: The #[external(\"public\")] macro uses this internally. Smart contract developers\n /// typically won't need to access this directly as arguments are automatically made available.\n ///\n /// # Returns\n /// * `Field` - Hash of the function arguments\n ///\n pub fn get_args_hash(mut self) -> Field {\n if !self.args_hash.is_some() {\n self.args_hash = Option::some((self.compute_args_hash)());\n }\n\n self.args_hash.unwrap_unchecked()\n }\n\n /// Returns the \"transaction fee\" for the current transaction. This is the final tx fee that will be deducted from\n /// the fee_payer's \"fee-juice\" balance (in the protocol's Base Rollup circuit).\n ///\n /// # Returns\n /// * `Field` - The actual, final cost of the transaction, taking into account: the actual gas used during the\n /// setup and app-logic phases, and the fixed amount of gas that's been allocated by the user for the teardown\n /// phase. I.e. effectiveL2FeePerGas * l2GasUsed + effectiveDAFeePerGas * daGasUsed\n ///\n /// This will return `0` during the \"setup\" and \"app-logic\" phases of tx execution (because the final tx fee is not\n /// known at that time). This will only return a nonzero value during the \"teardown\" phase of execution, where the\n /// final tx fee can actually be computed.\n ///\n /// Regardless of _when_ this function is called during the teardown phase, it will always return the same final tx\n /// fee value. The teardown phase does not consume a variable amount of gas: it always consumes a pre-allocated\n /// amount of gas, as specified by the user when they generate their tx.\n ///\n pub fn transaction_fee(_self: Self) -> Field {\n // Safety: AVM opcodes are constrained by the AVM itself\n unsafe {\n avm::transaction_fee()\n }\n }\n\n /// Returns the chain ID of the current network.\n ///\n /// This is similar to `block.chainid` in Solidity. Returns the unique identifier for the blockchain network this\n /// transaction is executing on.\n ///\n /// Helps prevent cross-chain replay attacks. Useful if implementing multi-chain contract logic.\n ///\n /// # Returns\n /// * `Field` - The chain ID as a field element\n ///\n pub fn chain_id(_self: Self) -> Field {\n // Safety: AVM opcodes are constrained by the AVM itself\n unsafe {\n avm::chain_id()\n }\n }\n\n /// Returns the Aztec protocol version that this transaction is executing under. Different versions may have\n /// different rules, opcodes, or cryptographic primitives.\n ///\n /// This is similar to how Ethereum has different EVM versions.\n ///\n /// Useful for forward/backward compatibility checks\n ///\n /// Not to be confused with contract versions; this is the protocol version.\n ///\n /// # Returns\n /// * `Field` - The protocol version as a field element\n ///\n pub fn version(_self: Self) -> Field {\n // Safety: AVM opcodes are constrained by the AVM itself\n unsafe {\n avm::version()\n }\n }\n /// Returns the current block number.\n ///\n /// This is similar to `block.number` in Solidity.\n ///\n /// Note: the current block number is only available within a public function (as opposed to a private function).\n ///\n /// Note: the time intervals between blocks should not be relied upon as being consistent:\n /// - Timestamps of blocks fall within a range, rather than at exact regular intervals.\n /// - Slots can be missed.\n /// - Protocol upgrades can completely change the intervals between blocks (and indeed the current roadmap plans to\n /// reduce the time between blocks, eventually). Use `context.timestamp()` for more-reliable time-based logic.\n ///\n /// # Returns\n /// * `u32` - The current block number\n ///\n pub fn block_number(_self: Self) -> u32 {\n // Safety: AVM opcodes are constrained by the AVM itself\n unsafe {\n avm::block_number()\n }\n }\n\n /// Returns the timestamp of the current block.\n ///\n /// This is similar to `block.timestamp` in Solidity.\n ///\n /// All functions of all transactions in a block share the exact same timestamp (even though technically each\n /// transaction is executed one-after-the-other).\n ///\n /// Important note: Timestamps of Aztec blocks are not at reliably-fixed intervals. The proposer of the block has\n /// some flexibility to choose a timestamp which is in a valid _range_: Obviously the timestamp of this block must\n /// be strictly greater than that of the previous block, and must must be less than the timestamp of whichever\n /// ethereum block the aztec block is proposed to. Furthermore, if the timestamp is not deemed close enough to the\n /// actual current time, the committee of validators will not attest to the block.\n ///\n /// # Returns\n /// * `u64` - Unix timestamp in seconds\n ///\n pub fn timestamp(_self: Self) -> u64 {\n // Safety: AVM opcodes are constrained by the AVM itself\n unsafe {\n avm::timestamp()\n }\n }\n\n /// Returns the fee per unit of L2 gas for this transaction (aka the \"L2 gas price\"), as chosen by the user.\n ///\n /// L2 gas covers the cost of executing public functions and handling side-effects within the AVM.\n ///\n /// # Returns\n /// * `u128` - Fee per unit of L2 gas\n ///\n /// Wallet developers should be mindful that the choice of gas price (which is publicly visible) can leak\n /// information about the user, e.g.:\n /// - which wallet software the user is using;\n /// - the amount of time which has elapsed from the time the user's wallet chose a gas price (at the going rate),\n /// to the time of tx submission. This can give clues about the proving time, and hence the nature of the tx.\n /// - the urgency of the transaction (which is kind of unavoidable, if the tx is indeed urgent).\n /// - the wealth of the user.\n /// - the exact user (if the gas price is explicitly chosen by the user to be some unique number like 0.123456789,\n /// or their favorite number). Wallet devs might wish to consider fuzzing the choice of gas price.\n ///\n pub fn min_fee_per_l2_gas(_self: Self) -> u128 {\n // Safety: AVM opcodes are constrained by the AVM itself\n unsafe {\n avm::min_fee_per_l2_gas()\n }\n }\n\n /// Returns the fee per unit of DA (Data Availability) gas (aka the \"DA gas price\").\n ///\n /// DA gas covers the cost of making transaction data available on L1.\n ///\n /// See the warning in `min_fee_per_l2_gas` for how gas prices can be leaky.\n ///\n /// # Returns\n /// * `u128` - Fee per unit of DA gas\n ///\n pub fn min_fee_per_da_gas(_self: Self) -> u128 {\n // Safety: AVM opcodes are constrained by the AVM itself\n unsafe {\n avm::min_fee_per_da_gas()\n }\n }\n\n /// Returns the remaining L2 gas available for this transaction.\n ///\n /// Different AVM opcodes consume different amounts of gas.\n ///\n /// # Returns\n /// * `u32` - Remaining L2 gas units\n ///\n pub fn l2_gas_left(_self: Self) -> u32 {\n // Safety: AVM opcodes are constrained by the AVM itself\n unsafe {\n avm::l2_gas_left()\n }\n }\n\n /// Returns the remaining DA (Data Availability) gas available for this transaction.\n ///\n /// DA gas is consumed when emitting data that needs to be made available on L1, such as public logs or state\n /// updates. All of the side-effects from the private part of the tx also consume DA gas before execution of any\n /// public functions even begins.\n ///\n /// # Returns\n /// * `u32` - Remaining DA gas units\n ///\n pub fn da_gas_left(_self: Self) -> u32 {\n // Safety: AVM opcodes are constrained by the AVM itself\n unsafe {\n avm::da_gas_left()\n }\n }\n\n /// Checks if the current execution is within a staticcall context, where no state changes or logs are allowed to\n /// be emitted (by this function or any nested function calls).\n ///\n /// # Returns\n /// * `bool` - True if in staticcall context, false otherwise\n ///\n pub fn is_static_call(_self: Self) -> bool {\n // Safety: AVM opcodes are constrained by the AVM itself\n unsafe { avm::is_static_call() } == 1\n }\n\n /// Reads raw field values from public storage. Reads N consecutive storage slots starting from the given slot.\n ///\n /// Very low-level function. Users should typically use the public state variable abstractions to perform reads:\n /// PublicMutable & PublicImmutable.\n ///\n /// # Arguments\n /// * `storage_slot` - The starting storage slot to read from\n ///\n /// # Returns\n /// * `[Field; N]` - Array of N field values from consecutive storage slots\n ///\n /// # Generic Parameters\n /// * `N` - the number of consecutive slots to return, starting from the `storage_slot`.\n ///\n pub fn raw_storage_read<let N: u32>(self: Self, storage_slot: Field) -> [Field; N] {\n let mut out = [0; N];\n for i in 0..N {\n // Safety: AVM opcodes are constrained by the AVM itself\n out[i] = unsafe { avm::storage_read(storage_slot + i as Field, self.this_address().to_field()) };\n }\n out\n }\n\n /// Reads a typed value from public storage.\n ///\n /// Low-level function. Users should typically use the public state variable abstractions to perform reads:\n /// PublicMutable & PublicImmutable.\n ///\n /// # Arguments\n /// * `storage_slot` - The storage slot to read from\n ///\n /// # Returns\n /// * `T` - The deserialized value from storage\n ///\n /// # Generic Parameters\n /// * `T` - The type that the caller expects to read from the `storage_slot`.\n ///\n pub fn storage_read<T>(self, storage_slot: Field) -> T\n where\n T: Packable,\n {\n T::unpack(self.raw_storage_read(storage_slot))\n }\n\n /// Writes raw field values to public storage. Writes to N consecutive storage slots starting from the given slot.\n ///\n /// Very low-level function. Users should typically use the public state variable abstractions to perform writes:\n /// PublicMutable & PublicImmutable.\n ///\n /// Public storage writes take effect immediately.\n ///\n /// # Arguments\n /// * `storage_slot` - The starting storage slot to write to\n /// * `values` - Array of N Fields to write to storage\n ///\n pub fn raw_storage_write<let N: u32>(_self: Self, storage_slot: Field, values: [Field; N]) {\n for i in 0..N {\n // Safety: AVM opcodes are constrained by the AVM itself\n unsafe { avm::storage_write(storage_slot + i as Field, values[i]) };\n }\n }\n\n /// Writes a typed value to public storage.\n ///\n /// Low-level function. Users should typically use the public state variable abstractions to perform writes:\n /// PublicMutable & PublicImmutable.\n ///\n /// # Arguments\n /// * `storage_slot` - The storage slot to write to\n /// * `value` - The typed value to write to storage\n ///\n /// # Generic Parameters\n /// * `T` - The type to write to storage.\n ///\n pub fn storage_write<T>(self, storage_slot: Field, value: T)\n where\n T: Packable,\n {\n self.raw_storage_write(storage_slot, value.pack());\n }\n}\n\nimpl Empty for PublicContext {\n fn empty() -> Self {\n PublicContext::new(|| 0)\n }\n}\n"
7300
+ "source": "use crate::{\n context::gas::GasOpts,\n hash::{\n compute_l1_to_l2_message_hash, compute_l1_to_l2_message_nullifier, compute_secret_hash,\n compute_siloed_nullifier,\n },\n oracle::avm,\n};\nuse crate::protocol::{\n abis::function_selector::FunctionSelector,\n address::{AztecAddress, EthAddress},\n constants::{MAX_U32_VALUE, NULL_MSG_SENDER_CONTRACT_ADDRESS},\n traits::{Empty, FromField, Packable, Serialize, ToField},\n utils::writer::Writer,\n};\n\n/// # PublicContext\n///\n/// The **main interface** between an #[external(\"public\")] function and the Aztec blockchain.\n///\n/// An instance of the PublicContext is initialized automatically at the outset of every public function, within the\n/// #[external(\"public\")] macro, so you'll never need to consciously instantiate this yourself.\n///\n/// The instance is always named `context`, and it will always be available within the body of every\n/// #[external(\"public\")] function in your smart contract.\n///\n/// Typical usage for a smart contract developer will be to call getter methods of the PublicContext.\n///\n/// _Pushing_ data and requests to the context is mostly handled within aztec-nr's own functions, so typically a smart\n/// contract developer won't need to call any setter methods directly.\n///\n/// ## Responsibilities\n/// - Exposes contextual data to a public function:\n/// - Data relating to how this public function was called:\n/// - msg_sender, this_address\n/// - Data relating to the current blockchain state:\n/// - timestamp, block_number, chain_id, version\n/// - Gas and fee information\n/// - Provides state access:\n/// - Read/write public storage (key-value mapping)\n/// - Check existence of notes and nullifiers (Some patterns use notes & nullifiers to store public (not private)\n/// information)\n/// - Enables consumption of L1->L2 messages.\n/// - Enables calls to other public smart contract functions:\n/// - Writes data to the blockchain:\n/// - Updates to public state variables\n/// - New public logs (for events)\n/// - New L2->L1 messages\n/// - New notes & nullifiers (E.g. pushing public info to notes/nullifiers, or for completing \"partial notes\")\n///\n/// ## Key Differences from Private Execution\n///\n/// Unlike private functions -- which are executed on the user's device and which can only reference historic state --\n/// public functions are executed by a block proposer and are executed \"live\" on the _current_ tip of the chain. This\n/// means public functions can:\n/// - Read and write _current_ public state\n/// - Immediately see the effects of earlier transactions in the same block\n///\n/// Also, public functions are executed within a zkVM (the \"AVM\"), so that they can _revert_ whilst still ensuring\n/// payment to the proposer and prover. (Private functions cannot revert: they either succeed, or they cannot be\n/// included).\n///\n/// ## Optimising Public Functions\n///\n/// Using the AVM to execute public functions means they compile down to \"AVM bytecode\" instead of the ACIR that\n/// private functions (standalone circuits) compile to. Therefore the approach to optimising a public function is\n/// fundamentally different from optimising a public function.\n///\npub struct PublicContext {\n pub args_hash: Option<Field>,\n pub compute_args_hash: fn() -> Field,\n}\n\nimpl Eq for PublicContext {\n fn eq(self, other: Self) -> bool {\n (self.args_hash == other.args_hash)\n // Can't compare the function compute_args_hash\n }\n}\n\nimpl PublicContext {\n /// Creates a new PublicContext instance.\n ///\n /// Low-level function: This is called automatically by the #[external(\"public\")] macro, so you shouldn't need to\n /// be called directly by smart contract developers.\n ///\n /// # Arguments\n /// * `compute_args_hash` - Function to compute the args_hash\n ///\n /// # Returns\n /// * A new PublicContext instance\n ///\n pub fn new(compute_args_hash: fn() -> Field) -> Self {\n PublicContext { args_hash: Option::none(), compute_args_hash }\n }\n\n /// Emits a _public_ log that will be visible onchain to everyone.\n ///\n /// # Arguments\n /// * `tag` - A tag placed at `fields[0]` of the emitted log. Nodes index logs by this value, allowing\n /// clients to efficiently query for matching logs without scanning all of them.\n /// * `log` - The data to log, must implement Serialize trait.\n ///\n /// ## Safety\n ///\n /// The `tag` should be domain-separated (e.g. via [`crate::protocol::hash::compute_log_tag`]) to prevent\n /// collisions between logs from different sources. Without domain separation, two unrelated log types that\n /// happen to share a raw tag value become indistinguishable. Prefer `self.emit(event)` for events, which\n /// handles tagging automatically.\n pub fn emit_public_log_unsafe<T>(_self: Self, tag: Field, log: T)\n where\n T: Serialize,\n {\n // We use a Writer to serialize the log directly after the tag, avoiding an extra O(n) copy that would\n // result from serializing first and then prepending the tag.\n let mut writer: Writer<1 + <T as Serialize>::N> = Writer::new();\n writer.write(tag);\n Serialize::stream_serialize(log, &mut writer);\n // Safety: AVM opcodes are constrained by the AVM itself\n unsafe { avm::emit_public_log(writer.finish().as_vector()) };\n }\n\n /// Checks if a given note hash exists in the note hash tree at a particular leaf_index.\n ///\n /// # Arguments\n /// * `note_hash` - The note hash to check for existence\n /// * `leaf_index` - The index where the note hash should be located\n ///\n /// # Returns\n /// * `bool` - True if the note hash exists at the specified index\n ///\n pub fn note_hash_exists(_self: Self, note_hash: Field, leaf_index: u64) -> bool {\n // Safety: AVM opcodes are constrained by the AVM itself\n unsafe {\n avm::note_hash_exists(note_hash, leaf_index)\n }\n }\n\n /// Checks if a specific L1-to-L2 message exists in the L1-to-L2 message tree at a particular leaf index.\n ///\n /// Common use cases include token bridging, cross-chain governance, and triggering L2 actions based on L1 events.\n ///\n /// This function should be called before attempting to consume an L1-to-L2 message.\n ///\n /// # Arguments\n /// * `msg_hash` - Hash of the L1-to-L2 message to check\n /// * `msg_leaf_index` - The index where the message should be located\n ///\n /// # Returns\n /// * `bool` - True if the message exists at the specified index\n ///\n /// # Advanced\n /// * Uses the AVM l1_to_l2_msg_exists opcode for tree lookup\n /// * Messages are copied from L1 Inbox to L2 by block proposers\n ///\n pub fn l1_to_l2_msg_exists(_self: Self, msg_hash: Field, msg_leaf_index: Field) -> bool {\n // Safety: AVM opcodes are constrained by the AVM itself TODO(alvaro): Make l1l2msg leaf index a u64 upstream\n unsafe {\n avm::l1_to_l2_msg_exists(msg_hash, msg_leaf_index as u64)\n }\n }\n\n /// Returns `true` if an `unsiloed_nullifier` has been emitted by `contract_address`.\n ///\n /// Note that unsiloed nullifiers are not the actual values stored in the nullifier tree: they are first siloed via\n /// [`crate::hash::compute_siloed_nullifier`] with the emitting contract's address.\n ///\n /// ## Use Cases\n ///\n /// Nullifiers are typically used as a _privacy-preserving_ record of a one-time action, but they can also be used\n /// to efficiently record _public_ one-time actions as well. This is cheaper than using public storage, and has the\n /// added benefit of the nullifier being emittable from a private function.\n ///\n /// An example is to check whether a contract has been published: we emit a nullifier that is deterministic and\n /// which has a _public_ preimage.\n ///\n /// ## Public vs Private\n ///\n /// In general, one should not attempt to prove nullifier non-existence in private, as that will not consider the\n /// possibility of the nullifier having been emitted in any transaction between the anchor block and the inclusion\n /// block. Private functions instead prove existence via\n /// [`crate::context::PrivateContext::assert_nullifier_exists`]\n /// and 'prove' non-existence by _emitting_ the nullifer, which would cause the transaction to fail if the\n /// nullifier existed.\n ///\n /// This is not the case in public functions, which **do** have access to the tip of the blockchain and so can\n /// reliably prove whether a nullifier exists or not.\n ///\n /// ## Safety\n ///\n /// While it is safe to rely on this function's return value to determine if a nullifier exists or not, it is often\n /// **not** safe to infer additional information from that. In particular, it is **unsafe** to infer that the\n /// existence of a nullifier emitted from a private function implies that all other side-effects of said private\n /// execution have been completed, more concretely that any enqueued public calls have been executed.\n ///\n /// For example, if a function in contract `A` privately emits nullifier `X` and then enqueues public function `Y`,\n /// then it is **unsafe** for a contract `B` to infer that `Y` has alredy executed simply because `X` exists.\n ///\n /// This is because **all** private transaction effects are committed _before_ enqueued public functions are run\n /// (in\n /// order to not reveal detailed timing information about the transaction), so it is possible to observe a\n /// nullifier that was emitted alongside the enqueuing of a public call **before** said call has been completed.\n ///\n /// ## Cost\n ///\n /// This emits the `CHECKNULLIFIEREXISTS` opcode, which conceptually performs a merkle inclusion proof on the\n /// nullifier tree (both when the nullifier exists and when it doesn't).\n pub fn nullifier_exists_unsafe(_self: Self, unsiloed_nullifier: Field, contract_address: AztecAddress) -> bool {\n let siloed_nullifier = compute_siloed_nullifier(contract_address, unsiloed_nullifier);\n // Safety: AVM opcodes are constrained by the AVM itself\n unsafe {\n avm::nullifier_exists(siloed_nullifier)\n }\n }\n\n /// Consumes a message sent from Ethereum (L1) to Aztec (L2) -- effectively marking it as \"read\".\n ///\n /// Use this function if you only want the message to ever be \"referred to\" once. Once consumed using this method,\n /// the message cannot be consumed again, because a nullifier is emitted. If your use case wants for the message to\n /// be read unlimited times, then you can always read any historic message from the L1-to-L2 messages tree, using\n /// the `l1_to_l2_msg_exists` method. Messages never technically get deleted from that tree.\n ///\n /// The message will first be inserted into an Aztec \"Inbox\" smart contract on L1. It will not be available for\n /// consumption immediately. Messages get copied-over from the L1 Inbox to L2 by the next Proposer in batches. So\n /// you will need to wait until the messages are copied before you can consume them.\n ///\n /// # Arguments\n /// * `content` - The message content that was sent from L1\n /// * `secret` - Secret value used for message privacy (if needed)\n /// * `sender` - Ethereum address that sent the message\n /// * `leaf_index` - Index of the message in the L1-to-L2 message tree\n ///\n /// # Advanced\n /// * Validates message existence in the L1-to-L2 message tree\n /// * Prevents double-consumption by emitting a nullifier\n /// * Message hash is computed from all parameters + chain context\n /// * Will revert if message doesn't exist or was already consumed\n ///\n pub fn consume_l1_to_l2_message(self: Self, content: Field, secret: Field, sender: EthAddress, leaf_index: Field) {\n let secret_hash = compute_secret_hash(secret);\n let message_hash = compute_l1_to_l2_message_hash(\n sender,\n self.chain_id(),\n /*recipient=*/\n self.this_address(),\n self.version(),\n content,\n secret_hash,\n leaf_index,\n );\n let nullifier = compute_l1_to_l2_message_nullifier(message_hash, secret);\n\n assert(!self.nullifier_exists_unsafe(nullifier, self.this_address()), \"L1-to-L2 message is already nullified\");\n assert(self.l1_to_l2_msg_exists(message_hash, leaf_index), \"Tried to consume nonexistent L1-to-L2 message\");\n\n self.push_nullifier(nullifier);\n }\n\n /// Sends an \"L2 -> L1 message\" from this function (Aztec, L2) to a smart contract on Ethereum (L1). L1 contracts\n /// which are designed to send/receive messages to/from Aztec are called \"Portal Contracts\".\n ///\n /// Common use cases include withdrawals, cross-chain asset transfers, and triggering L1 actions based on L2 state\n /// changes.\n ///\n /// The message will be inserted into an Aztec \"Outbox\" contract on L1, when this transaction's block is proposed\n /// to L1. Sending the message will not result in any immediate state changes in the target portal contract. The\n /// message will need to be manually consumed from the Outbox through a separate Ethereum transaction: a user will\n /// need to call a function of the portal contract -- a function specifically designed to make a call to the Outbox\n /// to consume the message. The message will only be available for consumption once the _epoch_ proof has been\n /// submitted. Given that there are multiple Aztec blocks within an epoch, it might take some time for this epoch\n /// proof to be submitted -- especially if the block was near the start of an epoch.\n ///\n /// # Arguments\n /// * `recipient` - Ethereum address that will receive the message\n /// * `content` - Message content (32 bytes as a Field element)\n ///\n pub fn message_portal(_self: Self, recipient: EthAddress, content: Field) {\n // Safety: AVM opcodes are constrained by the AVM itself\n unsafe { avm::send_l2_to_l1_msg(recipient, content) };\n }\n\n /// Calls a public function on another contract.\n ///\n /// Will revert if the called function reverts or runs out of gas.\n ///\n /// # Arguments\n /// * `contract_address` - Address of the contract to call\n /// * `function_selector` - Function to call on the target contract\n /// * `args` - Arguments to pass to the function\n /// * `gas_opts` - An optional allocation of gas to the called function.\n ///\n /// # Returns\n /// * `[Field]` - Return data from the called function\n ///\n pub unconstrained fn call_public_function<let N: u32>(\n _self: Self,\n contract_address: AztecAddress,\n function_selector: FunctionSelector,\n args: [Field; N],\n gas_opts: GasOpts,\n ) -> [Field] {\n let calldata = [function_selector.to_field()].concat(args);\n\n avm::call(\n gas_opts.l2_gas.unwrap_or(MAX_U32_VALUE),\n gas_opts.da_gas.unwrap_or(MAX_U32_VALUE),\n contract_address,\n calldata,\n );\n // Use success_copy to determine whether the call succeeded\n let success = avm::success_copy();\n\n let result_data = avm::returndata_copy(0, avm::returndata_size());\n if !success {\n // Rethrow the revert data.\n avm::revert(result_data);\n }\n result_data\n }\n\n /// Makes a read-only call to a public function on another contract.\n ///\n /// This is similar to Solidity's `staticcall`. The called function cannot modify state or emit events. Any nested\n /// calls are constrained to also be staticcalls.\n ///\n /// Useful for querying data from other contracts safely.\n ///\n /// Will revert if the called function reverts or runs out of gas.\n ///\n /// # Arguments\n /// * `contract_address` - Address of the contract to call\n /// * `function_selector` - Function to call on the target contract\n /// * `args` - Array of arguments to pass to the called function\n /// * `gas_opts` - An optional allocation of gas to the called function.\n ///\n /// # Returns\n /// * `[Field]` - Return data from the called function\n ///\n pub unconstrained fn static_call_public_function<let N: u32>(\n _self: Self,\n contract_address: AztecAddress,\n function_selector: FunctionSelector,\n args: [Field; N],\n gas_opts: GasOpts,\n ) -> [Field] {\n let calldata = [function_selector.to_field()].concat(args);\n\n avm::call_static(\n gas_opts.l2_gas.unwrap_or(MAX_U32_VALUE),\n gas_opts.da_gas.unwrap_or(MAX_U32_VALUE),\n contract_address,\n calldata,\n );\n // Use success_copy to determine whether the call succeeded\n let success = avm::success_copy();\n\n let result_data = avm::returndata_copy(0, avm::returndata_size());\n if !success {\n // Rethrow the revert data.\n avm::revert(result_data);\n }\n result_data\n }\n\n /// Adds a new note hash to the Aztec blockchain's global Note Hash Tree.\n ///\n /// Notes are ordinarily constructed and emitted by _private_ functions, to ensure that both the content of the\n /// note, and the contract that emitted the note, stay private.\n ///\n /// There are however some useful patterns whereby a note needs to contain _public_ data. The ability to push a new\n /// note_hash from a _public_ function means that notes can be injected with public data immediately -- as soon as\n /// the public value is known. The slower alternative would be to submit a follow-up transaction so that a private\n /// function can inject the data. Both are possible on Aztec.\n ///\n /// Search \"Partial Note\" for a very common pattern which enables a note to be \"partially\" populated with some data\n /// in a _private_ function, and then later \"completed\" with some data in a public function.\n ///\n /// # Arguments\n /// * `note_hash` - The hash of the note to add to the tree\n ///\n /// # Advanced\n /// * The note hash will be siloed with the contract address by the protocol\n ///\n pub fn push_note_hash(_self: Self, note_hash: Field) {\n // Safety: AVM opcodes are constrained by the AVM itself\n unsafe { avm::emit_note_hash(note_hash) };\n }\n\n /// Creates a new [nullifier](crate::nullifier).\n ///\n /// While nullifiers are primarily intended as a _privacy-preserving_ record of a one-time action, they can also\n /// be used to efficiently record _public_ one-time actions. This function allows creating nullifiers from public\n /// contract functions, which behave just like those created from private functions.\n ///\n /// ## Safety\n ///\n /// This is a low-level function that must be used with great care to avoid subtle corruption of contract state.\n ///\n /// In particular, callers must ensure all nullifiers created by a contract are properly domain-separated, so that\n /// unrelated components don't interfere with one another (e.g. a transaction nullifier accidentally marking a\n /// variable as initialized). Note nullifiers should only be created via\n /// [`crate::context::PrivateContext::push_nullifier_for_note_hash`].\n ///\n /// ## Advanced\n ///\n /// The raw `nullifier` is not what is inserted into the Aztec state tree: it will be first siloed by contract\n /// address via [`crate::protocol::hash::compute_siloed_nullifier`] in order to prevent accidental or malicious\n /// interference of nullifiers from different contracts.\n pub fn push_nullifier(_self: Self, nullifier: Field) {\n // Safety: AVM opcodes are constrained by the AVM itself\n unsafe { avm::emit_nullifier(nullifier) };\n }\n\n /// Returns the address of the current contract being executed.\n ///\n /// This is equivalent to `address(this)` in Solidity (hence the name). Use this to identify the current contract's\n /// address, commonly needed for access control or when interacting with other contracts.\n ///\n /// # Returns\n /// * `AztecAddress` - The contract address of the current function being executed.\n ///\n pub fn this_address(_self: Self) -> AztecAddress {\n // Safety: AVM opcodes are constrained by the AVM itself\n unsafe {\n avm::address()\n }\n }\n\n /// Returns the contract address that initiated this function call.\n ///\n /// This is similar to `msg.sender` in Solidity (hence the name).\n ///\n /// Important Note: If the calling function is a _private_ function, then it had the option of hiding its address\n /// when enqueuing this public function call. In such cases, this method will return `Option<AztecAddress>::none`.\n /// If the calling function is a _public_ function, it will always return an `Option<AztecAddress>::some` (i.e. a\n /// non-null value).\n ///\n /// # Returns\n /// * `Option<AztecAddress>` - The address of the smart contract that called this function (be it an app contract\n /// or a user's account contract).\n ///\n /// # Advanced\n /// * Value is provided by the AVM sender opcode\n /// * In nested calls, this is the immediate caller, not the original transaction sender\n ///\n pub fn maybe_msg_sender(_self: Self) -> Option<AztecAddress> {\n // Safety: AVM opcodes are constrained by the AVM itself\n let maybe_msg_sender = unsafe { avm::sender() };\n if maybe_msg_sender == NULL_MSG_SENDER_CONTRACT_ADDRESS {\n Option::none()\n } else {\n Option::some(maybe_msg_sender)\n }\n }\n\n /// Returns the function selector of the currently-executing function.\n ///\n /// This is similar to `msg.sig` in Solidity, returning the first 4 bytes of the function signature.\n ///\n /// # Returns\n /// * `FunctionSelector` - The 4-byte function identifier\n ///\n /// # Advanced\n /// * Extracted from the first element of calldata\n /// * Used internally for function dispatch in the AVM\n ///\n pub fn selector(_self: Self) -> FunctionSelector {\n // The selector is the first element of the calldata when calling a public function through dispatch.\n // Safety: AVM opcodes are constrained by the AVM itself.\n let raw_selector: [Field; 1] = unsafe { avm::calldata_copy(0, 1) };\n FunctionSelector::from_field(raw_selector[0])\n }\n\n /// Returns the hash of the arguments passed to the current function.\n ///\n /// Very low-level function: The #[external(\"public\")] macro uses this internally. Smart contract developers\n /// typically won't need to access this directly as arguments are automatically made available.\n ///\n /// # Returns\n /// * `Field` - Hash of the function arguments\n ///\n pub fn get_args_hash(mut self) -> Field {\n if !self.args_hash.is_some() {\n self.args_hash = Option::some((self.compute_args_hash)());\n }\n\n self.args_hash.unwrap_unchecked()\n }\n\n /// Returns the \"transaction fee\" for the current transaction. This is the final tx fee that will be deducted from\n /// the fee_payer's \"fee-juice\" balance (in the protocol's Base Rollup circuit).\n ///\n /// # Returns\n /// * `Field` - The actual, final cost of the transaction, taking into account: the actual gas used during the\n /// setup and app-logic phases, and the fixed amount of gas that's been allocated by the user for the teardown\n /// phase. I.e. effectiveL2FeePerGas * l2GasUsed + effectiveDAFeePerGas * daGasUsed\n ///\n /// This will return `0` during the \"setup\" and \"app-logic\" phases of tx execution (because the final tx fee is not\n /// known at that time). This will only return a nonzero value during the \"teardown\" phase of execution, where the\n /// final tx fee can actually be computed.\n ///\n /// Regardless of _when_ this function is called during the teardown phase, it will always return the same final tx\n /// fee value. The teardown phase does not consume a variable amount of gas: it always consumes a pre-allocated\n /// amount of gas, as specified by the user when they generate their tx.\n ///\n pub fn transaction_fee(_self: Self) -> Field {\n // Safety: AVM opcodes are constrained by the AVM itself\n unsafe {\n avm::transaction_fee()\n }\n }\n\n /// Returns the chain ID of the current network.\n ///\n /// This is similar to `block.chainid` in Solidity. Returns the unique identifier for the blockchain network this\n /// transaction is executing on.\n ///\n /// Helps prevent cross-chain replay attacks. Useful if implementing multi-chain contract logic.\n ///\n /// # Returns\n /// * `Field` - The chain ID as a field element\n ///\n pub fn chain_id(_self: Self) -> Field {\n // Safety: AVM opcodes are constrained by the AVM itself\n unsafe {\n avm::chain_id()\n }\n }\n\n /// Returns the Aztec protocol version that this transaction is executing under. Different versions may have\n /// different rules, opcodes, or cryptographic primitives.\n ///\n /// This is similar to how Ethereum has different EVM versions.\n ///\n /// Useful for forward/backward compatibility checks\n ///\n /// Not to be confused with contract versions; this is the protocol version.\n ///\n /// # Returns\n /// * `Field` - The protocol version as a field element\n ///\n pub fn version(_self: Self) -> Field {\n // Safety: AVM opcodes are constrained by the AVM itself\n unsafe {\n avm::version()\n }\n }\n /// Returns the current block number.\n ///\n /// This is similar to `block.number` in Solidity.\n ///\n /// Note: the current block number is only available within a public function (as opposed to a private function).\n ///\n /// Note: the time intervals between blocks should not be relied upon as being consistent:\n /// - Timestamps of blocks fall within a range, rather than at exact regular intervals.\n /// - Slots can be missed.\n /// - Protocol upgrades can completely change the intervals between blocks (and indeed the current roadmap plans to\n /// reduce the time between blocks, eventually). Use `context.timestamp()` for more-reliable time-based logic.\n ///\n /// # Returns\n /// * `u32` - The current block number\n ///\n pub fn block_number(_self: Self) -> u32 {\n // Safety: AVM opcodes are constrained by the AVM itself\n unsafe {\n avm::block_number()\n }\n }\n\n /// Returns the timestamp of the current block.\n ///\n /// This is similar to `block.timestamp` in Solidity.\n ///\n /// All functions of all transactions in a block share the exact same timestamp (even though technically each\n /// transaction is executed one-after-the-other).\n ///\n /// Important note: Timestamps of Aztec blocks are not at reliably-fixed intervals. The proposer of the block has\n /// some flexibility to choose a timestamp which is in a valid _range_: Obviously the timestamp of this block must\n /// be strictly greater than that of the previous block, and must must be less than the timestamp of whichever\n /// ethereum block the aztec block is proposed to. Furthermore, if the timestamp is not deemed close enough to the\n /// actual current time, the committee of validators will not attest to the block.\n ///\n /// # Returns\n /// * `u64` - Unix timestamp in seconds\n ///\n pub fn timestamp(_self: Self) -> u64 {\n // Safety: AVM opcodes are constrained by the AVM itself\n unsafe {\n avm::timestamp()\n }\n }\n\n /// Returns the fee per unit of L2 gas for this transaction (aka the \"L2 gas price\"), as chosen by the user.\n ///\n /// L2 gas covers the cost of executing public functions and handling side-effects within the AVM.\n ///\n /// # Returns\n /// * `u128` - Fee per unit of L2 gas\n ///\n /// Wallet developers should be mindful that the choice of gas price (which is publicly visible) can leak\n /// information about the user, e.g.:\n /// - which wallet software the user is using;\n /// - the amount of time which has elapsed from the time the user's wallet chose a gas price (at the going rate),\n /// to the time of tx submission. This can give clues about the proving time, and hence the nature of the tx.\n /// - the urgency of the transaction (which is kind of unavoidable, if the tx is indeed urgent).\n /// - the wealth of the user.\n /// - the exact user (if the gas price is explicitly chosen by the user to be some unique number like 0.123456789,\n /// or their favorite number). Wallet devs might wish to consider fuzzing the choice of gas price.\n ///\n pub fn min_fee_per_l2_gas(_self: Self) -> u128 {\n // Safety: AVM opcodes are constrained by the AVM itself\n unsafe {\n avm::min_fee_per_l2_gas()\n }\n }\n\n /// Returns the fee per unit of DA (Data Availability) gas (aka the \"DA gas price\").\n ///\n /// DA gas covers the cost of making transaction data available on L1.\n ///\n /// See the warning in `min_fee_per_l2_gas` for how gas prices can be leaky.\n ///\n /// # Returns\n /// * `u128` - Fee per unit of DA gas\n ///\n pub fn min_fee_per_da_gas(_self: Self) -> u128 {\n // Safety: AVM opcodes are constrained by the AVM itself\n unsafe {\n avm::min_fee_per_da_gas()\n }\n }\n\n /// Returns the remaining L2 gas available for this transaction.\n ///\n /// Different AVM opcodes consume different amounts of gas.\n ///\n /// # Returns\n /// * `u32` - Remaining L2 gas units\n ///\n pub fn l2_gas_left(_self: Self) -> u32 {\n // Safety: AVM opcodes are constrained by the AVM itself\n unsafe {\n avm::l2_gas_left()\n }\n }\n\n /// Returns the remaining DA (Data Availability) gas available for this transaction.\n ///\n /// DA gas is consumed when emitting data that needs to be made available on L1, such as public logs or state\n /// updates. All of the side-effects from the private part of the tx also consume DA gas before execution of any\n /// public functions even begins.\n ///\n /// # Returns\n /// * `u32` - Remaining DA gas units\n ///\n pub fn da_gas_left(_self: Self) -> u32 {\n // Safety: AVM opcodes are constrained by the AVM itself\n unsafe {\n avm::da_gas_left()\n }\n }\n\n /// Checks if the current execution is within a staticcall context, where no state changes or logs are allowed to\n /// be emitted (by this function or any nested function calls).\n ///\n /// # Returns\n /// * `bool` - True if in staticcall context, false otherwise\n ///\n pub fn is_static_call(_self: Self) -> bool {\n // Safety: AVM opcodes are constrained by the AVM itself\n unsafe {\n avm::is_static_call()\n }\n }\n\n /// Reads raw field values from public storage. Reads N consecutive storage slots starting from the given slot.\n ///\n /// Very low-level function. Users should typically use the public state variable abstractions to perform reads:\n /// PublicMutable & PublicImmutable.\n ///\n /// # Arguments\n /// * `storage_slot` - The starting storage slot to read from\n ///\n /// # Returns\n /// * `[Field; N]` - Array of N field values from consecutive storage slots\n ///\n /// # Generic Parameters\n /// * `N` - the number of consecutive slots to return, starting from the `storage_slot`.\n ///\n pub fn raw_storage_read<let N: u32>(self: Self, storage_slot: Field) -> [Field; N] {\n let mut out = [0; N];\n for i in 0..N {\n // Safety: AVM opcodes are constrained by the AVM itself\n out[i] = unsafe { avm::storage_read(storage_slot + i as Field, self.this_address().to_field()) };\n }\n out\n }\n\n /// Reads a typed value from public storage.\n ///\n /// Low-level function. Users should typically use the public state variable abstractions to perform reads:\n /// PublicMutable & PublicImmutable.\n ///\n /// # Arguments\n /// * `storage_slot` - The storage slot to read from\n ///\n /// # Returns\n /// * `T` - The deserialized value from storage\n ///\n /// # Generic Parameters\n /// * `T` - The type that the caller expects to read from the `storage_slot`.\n ///\n pub fn storage_read<T>(self, storage_slot: Field) -> T\n where\n T: Packable,\n {\n T::unpack(self.raw_storage_read(storage_slot))\n }\n\n /// Writes raw field values to public storage. Writes to N consecutive storage slots starting from the given slot.\n ///\n /// Very low-level function. Users should typically use the public state variable abstractions to perform writes:\n /// PublicMutable & PublicImmutable.\n ///\n /// Public storage writes take effect immediately.\n ///\n /// # Arguments\n /// * `storage_slot` - The starting storage slot to write to\n /// * `values` - Array of N Fields to write to storage\n ///\n pub fn raw_storage_write<let N: u32>(_self: Self, storage_slot: Field, values: [Field; N]) {\n for i in 0..N {\n // Safety: AVM opcodes are constrained by the AVM itself\n unsafe { avm::storage_write(storage_slot + i as Field, values[i]) };\n }\n }\n\n /// Writes a typed value to public storage.\n ///\n /// Low-level function. Users should typically use the public state variable abstractions to perform writes:\n /// PublicMutable & PublicImmutable.\n ///\n /// # Arguments\n /// * `storage_slot` - The storage slot to write to\n /// * `value` - The typed value to write to storage\n ///\n /// # Generic Parameters\n /// * `T` - The type to write to storage.\n ///\n pub fn storage_write<T>(self, storage_slot: Field, value: T)\n where\n T: Packable,\n {\n self.raw_storage_write(storage_slot, value.pack());\n }\n}\n\nimpl Empty for PublicContext {\n fn empty() -> Self {\n PublicContext::new(|| 0)\n }\n}\n"
7329
7301
  },
7330
7302
  "69": {
7331
7303
  "function_locations": [
@@ -7641,35 +7613,35 @@
7641
7613
  },
7642
7614
  {
7643
7615
  "name": "compute_app_siloed_shared_secret",
7644
- "start": 1303
7616
+ "start": 1485
7645
7617
  },
7646
7618
  {
7647
7619
  "name": "derive_shared_secret_subkey",
7648
- "start": 1694
7620
+ "start": 1876
7649
7621
  },
7650
7622
  {
7651
7623
  "name": "derive_shared_secret_field_mask",
7652
- "start": 2012
7624
+ "start": 2194
7653
7625
  },
7654
7626
  {
7655
7627
  "name": "test_consistency_with_typescript",
7656
- "start": 2154
7628
+ "start": 2336
7657
7629
  },
7658
7630
  {
7659
7631
  "name": "test_shared_secret_computation_in_both_directions",
7660
- "start": 3268
7632
+ "start": 3450
7661
7633
  },
7662
7634
  {
7663
7635
  "name": "test_shared_secret_computation_from_address_in_both_directions",
7664
- "start": 3807
7636
+ "start": 4017
7665
7637
  },
7666
7638
  {
7667
7639
  "name": "test_app_siloed_shared_secret_differs_per_contract",
7668
- "start": 5040
7640
+ "start": 5278
7669
7641
  }
7670
7642
  ],
7671
7643
  "path": "/home/aztec-dev/aztec-packages/noir-projects/aztec-nr/aztec/src/keys/ecdh_shared_secret.nr",
7672
- "source": "use crate::protocol::{\n address::aztec_address::AztecAddress,\n constants::{DOM_SEP__APP_SILOED_ECDH_SHARED_SECRET, DOM_SEP__ECDH_FIELD_MASK, DOM_SEP__ECDH_SUBKEY},\n hash::poseidon2_hash_with_separator,\n point::Point,\n scalar::Scalar,\n traits::{FromField, ToField},\n};\nuse std::{embedded_curve_ops::multi_scalar_mul, ops::Neg};\n\n/// Computes a standard ECDH shared secret: secret * public_key = shared_secret.\n///\n/// The input secret is known only to one party. The output shared secret can be derived given knowledge of\n/// `public_key`'s key-pair and the public ephemeral secret, using this same function (with reversed inputs).\n///\n/// E.g.: Epk = esk * G // ephemeral key-pair\n/// Pk = sk * G // recipient key-pair\n/// Shared secret S = esk * Pk = sk * Epk\n///\n/// See also: https://en.wikipedia.org/wiki/Elliptic-curve_Diffie%E2%80%93Hellman\npub fn derive_ecdh_shared_secret(secret: Scalar, public_key: Point) -> Point {\n multi_scalar_mul([public_key], [secret])\n}\n\n/// Computes an app-siloed shared secret from a raw ECDH shared secret point and a contract address.\n///\n/// `s_app = h(DOM_SEP__APP_SILOED_ECDH_SHARED_SECRET, S.x, S.y, contract_address)`\npub(crate) fn compute_app_siloed_shared_secret(shared_secret: Point, contract_address: AztecAddress) -> Field {\n poseidon2_hash_with_separator(\n [shared_secret.x, shared_secret.y, contract_address.to_field()],\n DOM_SEP__APP_SILOED_ECDH_SHARED_SECRET,\n )\n}\n\n/// Derives an indexed subkey from an app-siloed shared secret, used for AES key/IV derivation.\n///\n/// `s_i = h(DOM_SEP__ECDH_SUBKEY + i, s_app)`\npub(crate) fn derive_shared_secret_subkey(s_app: Field, index: u32) -> Field {\n poseidon2_hash_with_separator([s_app], DOM_SEP__ECDH_SUBKEY + index)\n}\n\n/// Derives an indexed field mask from an app-siloed shared secret, used for masking ciphertext fields.\n///\n/// `m_i = h(DOM_SEP__ECDH_FIELD_MASK + i, s_app)`\npub(crate) fn derive_shared_secret_field_mask(s_app: Field, index: u32) -> Field {\n poseidon2_hash_with_separator([s_app], DOM_SEP__ECDH_FIELD_MASK + index)\n}\n\n#[test]\nunconstrained fn test_consistency_with_typescript() {\n let secret = Scalar {\n lo: 0x00000000000000000000000000000000649e7ca01d9de27b21624098b897babd,\n hi: 0x0000000000000000000000000000000023b3127c127b1f29a7adff5cccf8fb06,\n };\n let point = Point {\n x: 0x2688431c705a5ff3e6c6f2573c9e3ba1c1026d2251d0dbbf2d810aa53fd1d186,\n y: 0x1e96887b117afca01c00468264f4f80b5bb16d94c1808a448595f115556e5c8e,\n is_infinite: false,\n };\n\n let shared_secret = derive_ecdh_shared_secret(secret, point);\n\n // This is just pasted from a test run. The original typescript code from which this could be generated seems to\n // have been deleted by someone, and soon the typescript code for encryption and decryption won't be needed, so\n // this will have to do.\n let hard_coded_shared_secret = Point {\n x: 0x15d55a5b3b2caa6a6207f313f05c5113deba5da9927d6421bcaa164822b911bc,\n y: 0x0974c3d0825031ae933243d653ebb1a0b08b90ee7f228f94c5c74739ea3c871e,\n is_infinite: false,\n };\n assert_eq(shared_secret, hard_coded_shared_secret);\n}\n\n#[test]\nunconstrained fn test_shared_secret_computation_in_both_directions() {\n let secret_a = Scalar { lo: 0x1234, hi: 0x2345 };\n let secret_b = Scalar { lo: 0x3456, hi: 0x4567 };\n\n let pk_a = std::embedded_curve_ops::fixed_base_scalar_mul(secret_a);\n let pk_b = std::embedded_curve_ops::fixed_base_scalar_mul(secret_b);\n\n let shared_secret = derive_ecdh_shared_secret(secret_a, pk_b);\n let shared_secret_alt = derive_ecdh_shared_secret(secret_b, pk_a);\n\n assert_eq(shared_secret, shared_secret_alt);\n}\n\n#[test]\nunconstrained fn test_shared_secret_computation_from_address_in_both_directions() {\n let secret_a = Scalar { lo: 0x1234, hi: 0x2345 };\n let secret_b = Scalar { lo: 0x3456, hi: 0x4567 };\n\n let mut pk_a = std::embedded_curve_ops::fixed_base_scalar_mul(secret_a);\n let mut pk_b = std::embedded_curve_ops::fixed_base_scalar_mul(secret_b);\n\n let address_b = AztecAddress::from_field(pk_b.x);\n\n // We were lazy in deriving the secret keys, and didn't check the resulting y-coordinates of the pk_a or pk_b to be\n // less than half the field modulus. If needed, we negate the pk's so that they yield valid address points. (We\n // could also have negated the secrets, but there's no negate method for EmbeddedCurvesScalar).\n pk_a = if (AztecAddress::from_field(pk_a.x).to_address_point().unwrap().inner == pk_a) {\n pk_a\n } else {\n pk_a.neg()\n };\n pk_b = if (address_b.to_address_point().unwrap().inner == pk_b) {\n pk_b\n } else {\n pk_b.neg()\n };\n\n let shared_secret = derive_ecdh_shared_secret(secret_a, address_b.to_address_point().unwrap().inner);\n let shared_secret_alt = derive_ecdh_shared_secret(secret_b, pk_a);\n\n assert_eq(shared_secret, shared_secret_alt);\n}\n\n#[test]\nunconstrained fn test_app_siloed_shared_secret_differs_per_contract() {\n let secret_a = Scalar { lo: 0x1234, hi: 0x2345 };\n let pk_b = std::embedded_curve_ops::fixed_base_scalar_mul(Scalar { lo: 0x3456, hi: 0x4567 });\n\n let shared_secret = derive_ecdh_shared_secret(secret_a, pk_b);\n\n let contract_a = AztecAddress::from_field(0xAAAA);\n let contract_b = AztecAddress::from_field(0xBBBB);\n\n let s_app_a = compute_app_siloed_shared_secret(shared_secret, contract_a);\n let s_app_b = compute_app_siloed_shared_secret(shared_secret, contract_b);\n\n assert(s_app_a != s_app_b, \"app-siloed secrets must differ for different contracts\");\n}\n"
7644
+ "source": "use crate::protocol::{\n address::aztec_address::AztecAddress,\n constants::{DOM_SEP__APP_SILOED_ECDH_SHARED_SECRET, DOM_SEP__ECDH_FIELD_MASK, DOM_SEP__ECDH_SUBKEY},\n hash::poseidon2_hash_with_separator,\n point::Point,\n scalar::Scalar,\n traits::{FromField, ToField},\n};\nuse std::{embedded_curve_ops::multi_scalar_mul, ops::Neg};\n\n/// Computes a standard ECDH shared secret: secret * public_key = shared_secret.\n///\n/// The input secret is known only to one party. The output shared secret can be derived given knowledge of\n/// `public_key`'s key-pair and the public ephemeral secret, using this same function (with reversed inputs).\n///\n/// E.g.: Epk = esk * G // ephemeral key-pair\n/// Pk = sk * G // recipient key-pair\n/// Shared secret S = esk * Pk = sk * Epk\n///\n/// See also: https://en.wikipedia.org/wiki/Elliptic-curve_Diffie%E2%80%93Hellman\npub fn derive_ecdh_shared_secret(secret: Scalar, public_key: Point) -> Point {\n // TODO(F-553): Drop the `.to_embedded()` / `.into()` round-trip once the custom `Point` wrapper is removed and we\n // use `EmbeddedCurvePoint` directly.\n multi_scalar_mul([public_key.to_embedded()], [secret]).into()\n}\n\n/// Computes an app-siloed shared secret from a raw ECDH shared secret point and a contract address.\n///\n/// `s_app = h(DOM_SEP__APP_SILOED_ECDH_SHARED_SECRET, S.x, S.y, contract_address)`\npub(crate) fn compute_app_siloed_shared_secret(shared_secret: Point, contract_address: AztecAddress) -> Field {\n poseidon2_hash_with_separator(\n [shared_secret.x, shared_secret.y, contract_address.to_field()],\n DOM_SEP__APP_SILOED_ECDH_SHARED_SECRET,\n )\n}\n\n/// Derives an indexed subkey from an app-siloed shared secret, used for AES key/IV derivation.\n///\n/// `s_i = h(DOM_SEP__ECDH_SUBKEY + i, s_app)`\npub(crate) fn derive_shared_secret_subkey(s_app: Field, index: u32) -> Field {\n poseidon2_hash_with_separator([s_app], DOM_SEP__ECDH_SUBKEY + index)\n}\n\n/// Derives an indexed field mask from an app-siloed shared secret, used for masking ciphertext fields.\n///\n/// `m_i = h(DOM_SEP__ECDH_FIELD_MASK + i, s_app)`\npub(crate) fn derive_shared_secret_field_mask(s_app: Field, index: u32) -> Field {\n poseidon2_hash_with_separator([s_app], DOM_SEP__ECDH_FIELD_MASK + index)\n}\n\n#[test]\nunconstrained fn test_consistency_with_typescript() {\n let secret = Scalar {\n lo: 0x00000000000000000000000000000000649e7ca01d9de27b21624098b897babd,\n hi: 0x0000000000000000000000000000000023b3127c127b1f29a7adff5cccf8fb06,\n };\n let point = Point {\n x: 0x2688431c705a5ff3e6c6f2573c9e3ba1c1026d2251d0dbbf2d810aa53fd1d186,\n y: 0x1e96887b117afca01c00468264f4f80b5bb16d94c1808a448595f115556e5c8e,\n is_infinite: false,\n };\n\n let shared_secret = derive_ecdh_shared_secret(secret, point);\n\n // This is just pasted from a test run. The original typescript code from which this could be generated seems to\n // have been deleted by someone, and soon the typescript code for encryption and decryption won't be needed, so\n // this will have to do.\n let hard_coded_shared_secret = Point {\n x: 0x15d55a5b3b2caa6a6207f313f05c5113deba5da9927d6421bcaa164822b911bc,\n y: 0x0974c3d0825031ae933243d653ebb1a0b08b90ee7f228f94c5c74739ea3c871e,\n is_infinite: false,\n };\n assert_eq(shared_secret, hard_coded_shared_secret);\n}\n\n#[test]\nunconstrained fn test_shared_secret_computation_in_both_directions() {\n let secret_a = Scalar { lo: 0x1234, hi: 0x2345 };\n let secret_b = Scalar { lo: 0x3456, hi: 0x4567 };\n\n let pk_a: Point = std::embedded_curve_ops::fixed_base_scalar_mul(secret_a).into();\n let pk_b: Point = std::embedded_curve_ops::fixed_base_scalar_mul(secret_b).into();\n\n let shared_secret = derive_ecdh_shared_secret(secret_a, pk_b);\n let shared_secret_alt = derive_ecdh_shared_secret(secret_b, pk_a);\n\n assert_eq(shared_secret, shared_secret_alt);\n}\n\n#[test]\nunconstrained fn test_shared_secret_computation_from_address_in_both_directions() {\n let secret_a = Scalar { lo: 0x1234, hi: 0x2345 };\n let secret_b = Scalar { lo: 0x3456, hi: 0x4567 };\n\n let mut pk_a: Point = std::embedded_curve_ops::fixed_base_scalar_mul(secret_a).into();\n let mut pk_b: Point = std::embedded_curve_ops::fixed_base_scalar_mul(secret_b).into();\n\n let address_b = AztecAddress::from_field(pk_b.x);\n\n // We were lazy in deriving the secret keys, and didn't check the resulting y-coordinates of the pk_a or pk_b to be\n // less than half the field modulus. If needed, we negate the pk's so that they yield valid address points. (We\n // could also have negated the secrets, but there's no negate method for EmbeddedCurvesScalar).\n pk_a = if (AztecAddress::from_field(pk_a.x).to_address_point().unwrap().inner == pk_a) {\n pk_a\n } else {\n pk_a.neg()\n };\n pk_b = if (address_b.to_address_point().unwrap().inner == pk_b) {\n pk_b\n } else {\n pk_b.neg()\n };\n\n let shared_secret = derive_ecdh_shared_secret(secret_a, address_b.to_address_point().unwrap().inner);\n let shared_secret_alt = derive_ecdh_shared_secret(secret_b, pk_a);\n\n assert_eq(shared_secret, shared_secret_alt);\n}\n\n#[test]\nunconstrained fn test_app_siloed_shared_secret_differs_per_contract() {\n let secret_a = Scalar { lo: 0x1234, hi: 0x2345 };\n let pk_b: Point = std::embedded_curve_ops::fixed_base_scalar_mul(Scalar { lo: 0x3456, hi: 0x4567 }).into();\n\n let shared_secret = derive_ecdh_shared_secret(secret_a, pk_b);\n\n let contract_a = AztecAddress::from_field(0xAAAA);\n let contract_b = AztecAddress::from_field(0xBBBB);\n\n let s_app_a = compute_app_siloed_shared_secret(shared_secret, contract_a);\n let s_app_b = compute_app_siloed_shared_secret(shared_secret, contract_b);\n\n assert(s_app_a != s_app_b, \"app-siloed secrets must differ for different contracts\");\n}\n"
7673
7645
  },
7674
7646
  "97": {
7675
7647
  "function_locations": [
@@ -7757,7 +7729,7 @@
7757
7729
  }
7758
7730
  ],
7759
7731
  "path": "/home/aztec-dev/aztec-packages/noir-projects/aztec-nr/aztec/src/macros/aztec/compute_note_hash_and_nullifier.nr",
7760
- "source": "use crate::logging;\nuse crate::macros::{notes::NOTES, utils::get_trait_impl_method};\n\n/// Generates two contract library methods called `_compute_note_hash` and `_compute_note_nullifier`, plus a\n/// (deprecated) wrapper called `_compute_note_hash_and_nullifier`, which are used for note discovery (i.e. these are\n/// of the `aztec::messages::discovery::ComputeNoteHash` and `aztec::messages::discovery::ComputeNoteNullifier` types).\npub(crate) comptime fn generate_contract_library_methods_compute_note_hash_and_nullifier() -> Quoted {\n let compute_note_hash = generate_contract_library_method_compute_note_hash();\n let compute_note_nullifier = generate_contract_library_method_compute_note_nullifier();\n\n quote {\n $compute_note_hash\n $compute_note_nullifier\n\n /// Unpacks an array into a note corresponding to `note_type_id` and then computes its note hash (non-siloed) and inner nullifier (non-siloed) assuming the note has been inserted into the note hash tree with `note_nonce`.\n ///\n /// This function is automatically injected by the `#[aztec]` macro.\n #[contract_library_method]\n #[allow(dead_code)]\n unconstrained fn _compute_note_hash_and_nullifier(\n packed_note: BoundedVec<Field, aztec::messages::logs::note::MAX_NOTE_PACKED_LEN>,\n owner: aztec::protocol::address::AztecAddress,\n storage_slot: Field,\n note_type_id: Field,\n contract_address: aztec::protocol::address::AztecAddress,\n randomness: Field,\n note_nonce: Field,\n ) -> Option<aztec::messages::discovery::NoteHashAndNullifier> {\n _compute_note_hash(packed_note, owner, storage_slot, note_type_id, contract_address, randomness).map(|note_hash| {\n\n let siloed_note_hash = aztec::protocol::hash::compute_siloed_note_hash(contract_address, note_hash);\n let unique_note_hash = aztec::protocol::hash::compute_unique_note_hash(note_nonce, siloed_note_hash);\n \n let inner_nullifier = _compute_note_nullifier(unique_note_hash, packed_note, owner, storage_slot, note_type_id, contract_address, randomness);\n\n aztec::messages::discovery::NoteHashAndNullifier {\n note_hash,\n inner_nullifier,\n }\n })\n }\n }\n}\n\ncomptime fn generate_contract_library_method_compute_note_hash() -> Quoted {\n if NOTES.len() == 0 {\n // Contracts with no notes still implement this function to avoid having special-casing, the implementation\n // simply throws immediately.\n quote {\n /// This contract does not use private notes, so this function should never be called as it will unconditionally fail.\n ///\n /// This function is automatically injected by the `#[aztec]` macro.\n #[contract_library_method]\n unconstrained fn _compute_note_hash(\n _packed_note: BoundedVec<Field, aztec::messages::logs::note::MAX_NOTE_PACKED_LEN>,\n _owner: aztec::protocol::address::AztecAddress,\n _storage_slot: Field,\n _note_type_id: Field,\n _contract_address: aztec::protocol::address::AztecAddress,\n _randomness: Field,\n ) -> Option<Field> {\n panic(f\"This contract does not use private notes\")\n }\n }\n } else {\n // Contracts that do define notes produce an if-else chain where `note_type_id` is matched against the\n // `get_note_type_id()` function of each note type that we know of, in order to identify the note type. Once we\n // know it we call the correct `unpack` method from the `Packable` trait to obtain the underlying note type, and\n // compute the note hash (non-siloed).\n\n // We resolve the log format calls here so that the resulting Quoted values can be spliced into the quote\n // block below.\n let warn_length_mismatch = logging::aztecnr_warn_log_format(\n \"Packed note length mismatch for note type id {0}: expected {1} fields, got {2}. Skipping note.\",\n );\n let warn_unknown_note_type = logging::aztecnr_warn_log_format(\"Unknown note type id {0}. Skipping note.\");\n\n let mut if_note_type_id_match_statements_list = @[];\n for i in 0..NOTES.len() {\n let typ = NOTES.get(i);\n\n let get_note_type_id = get_trait_impl_method(\n typ,\n quote { crate::note::note_interface::NoteType },\n quote { get_id },\n );\n let unpack = get_trait_impl_method(\n typ,\n quote { crate::protocol::traits::Packable },\n quote { unpack },\n );\n\n let compute_note_hash = get_trait_impl_method(\n typ,\n quote { crate::note::note_interface::NoteHash },\n quote { compute_note_hash },\n );\n\n let if_or_else_if = if i == 0 {\n quote { if }\n } else {\n quote { else if }\n };\n\n if_note_type_id_match_statements_list = if_note_type_id_match_statements_list.push_back(\n quote {\n $if_or_else_if note_type_id == $get_note_type_id() {\n // As an extra safety check we make sure that the packed_note BoundedVec has the expected\n // length, since we're about to interpret its raw storage as a fixed-size array by calling the\n // unpack function on it.\n let expected_len = <$typ as $crate::protocol::traits::Packable>::N;\n let actual_len = packed_note.len();\n if actual_len != expected_len {\n $warn_length_mismatch([note_type_id, expected_len as Field, actual_len as Field]);\n Option::none()\n } else {\n let note = $unpack(aztec::utils::array::subarray(packed_note.storage(), 0));\n\n Option::some($compute_note_hash(note, owner, storage_slot, randomness))\n }\n }\n },\n );\n }\n\n let if_note_type_id_match_statements = if_note_type_id_match_statements_list.join(quote {});\n\n quote {\n /// Unpacks an array into a note corresponding to `note_type_id` and then computes its note hash (non-siloed).\n ///\n /// The signature of this function notably matches the `aztec::messages::discovery::ComputeNoteHash` type, and so it can be used to call functions from that module such as `do_sync_state` and `attempt_note_discovery`.\n ///\n /// This function is automatically injected by the `#[aztec]` macro.\n #[contract_library_method]\n unconstrained fn _compute_note_hash(\n packed_note: BoundedVec<Field, aztec::messages::logs::note::MAX_NOTE_PACKED_LEN>,\n owner: aztec::protocol::address::AztecAddress,\n storage_slot: Field,\n note_type_id: Field,\n _contract_address: aztec::protocol::address::AztecAddress,\n randomness: Field,\n ) -> Option<Field> {\n $if_note_type_id_match_statements\n else {\n $warn_unknown_note_type([note_type_id]);\n Option::none()\n }\n }\n }\n }\n}\n\ncomptime fn generate_contract_library_method_compute_note_nullifier() -> Quoted {\n if NOTES.len() == 0 {\n // Contracts with no notes still implement this function to avoid having special-casing, the implementation\n // simply throws immediately.\n quote {\n /// This contract does not use private notes, so this function should never be called as it will unconditionally fail.\n ///\n /// This function is automatically injected by the `#[aztec]` macro.\n #[contract_library_method]\n unconstrained fn _compute_note_nullifier(\n _unique_note_hash: Field,\n _packed_note: BoundedVec<Field, aztec::messages::logs::note::MAX_NOTE_PACKED_LEN>,\n _owner: aztec::protocol::address::AztecAddress,\n _storage_slot: Field,\n _note_type_id: Field,\n _contract_address: aztec::protocol::address::AztecAddress,\n _randomness: Field,\n ) -> Option<Field> {\n panic(f\"This contract does not use private notes\")\n }\n }\n } else {\n // Contracts that do define notes produce an if-else chain where `note_type_id` is matched against the\n // `get_note_type_id()` function of each note type that we know of, in order to identify the note type. Once we\n // know it we call the correct `unpack` method from the `Packable` trait to obtain the underlying note type, and\n // compute the inner nullifier (non-siloed).\n\n // We resolve the log format calls here so that the resulting Quoted values can be spliced into the quote\n // block below.\n let warn_length_mismatch = logging::aztecnr_warn_log_format(\n \"Packed note length mismatch for note type id {0}: expected {1} fields, got {2}. Skipping note.\",\n );\n let warn_unknown_note_type = logging::aztecnr_warn_log_format(\"Unknown note type id {0}. Skipping note.\");\n\n let mut if_note_type_id_match_statements_list = @[];\n for i in 0..NOTES.len() {\n let typ = NOTES.get(i);\n\n let get_note_type_id = get_trait_impl_method(\n typ,\n quote { crate::note::note_interface::NoteType },\n quote { get_id },\n );\n let unpack = get_trait_impl_method(\n typ,\n quote { crate::protocol::traits::Packable },\n quote { unpack },\n );\n\n let compute_nullifier_unconstrained = get_trait_impl_method(\n typ,\n quote { crate::note::note_interface::NoteHash },\n quote { compute_nullifier_unconstrained },\n );\n\n let if_or_else_if = if i == 0 {\n quote { if }\n } else {\n quote { else if }\n };\n\n if_note_type_id_match_statements_list = if_note_type_id_match_statements_list.push_back(\n quote {\n $if_or_else_if note_type_id == $get_note_type_id() {\n // As an extra safety check we make sure that the packed_note BoundedVec has the expected\n // length, since we're about to interpret its raw storage as a fixed-size array by calling the\n // unpack function on it.\n let expected_len = <$typ as $crate::protocol::traits::Packable>::N;\n let actual_len = packed_note.len();\n if actual_len != expected_len {\n $warn_length_mismatch([note_type_id, expected_len as Field, actual_len as Field]);\n Option::none()\n } else {\n let note = $unpack(aztec::utils::array::subarray(packed_note.storage(), 0));\n\n // The message discovery process finds settled notes, that is, notes that were created in\n // prior transactions and are therefore already part of the note hash tree. The note hash\n // for nullification is hence the unique note hash.\n $compute_nullifier_unconstrained(note, owner, unique_note_hash)\n }\n }\n },\n );\n }\n\n let if_note_type_id_match_statements = if_note_type_id_match_statements_list.join(quote {});\n\n quote {\n /// Computes a note's inner nullifier (non-siloed) given its unique note hash, preimage and extra data.\n ///\n /// The signature of this function notably matches the `aztec::messages::discovery::ComputeNoteNullifier` type, and so it can be used to call functions from that module such as `do_sync_state` and `attempt_note_discovery`.\n ///\n /// This function is automatically injected by the `#[aztec]` macro.\n #[contract_library_method]\n unconstrained fn _compute_note_nullifier(\n unique_note_hash: Field,\n packed_note: BoundedVec<Field, aztec::messages::logs::note::MAX_NOTE_PACKED_LEN>,\n owner: aztec::protocol::address::AztecAddress,\n _storage_slot: Field,\n note_type_id: Field,\n _contract_address: aztec::protocol::address::AztecAddress,\n _randomness: Field,\n ) -> Option<Field> {\n $if_note_type_id_match_statements\n else {\n $warn_unknown_note_type([note_type_id]);\n Option::none()\n }\n }\n }\n }\n}\n"
7732
+ "source": "use crate::logging;\nuse crate::macros::{notes::NOTES, utils::get_trait_impl_method};\n\n/// Generates two contract library methods called `_compute_note_hash` and `_compute_note_nullifier`, plus a\n/// (deprecated) wrapper called `_compute_note_hash_and_nullifier`, which are used for note discovery (i.e. these are\n/// of the `aztec::messages::discovery::ComputeNoteHash` and `aztec::messages::discovery::ComputeNoteNullifier` types).\npub(crate) comptime fn generate_contract_library_methods_compute_note_hash_and_nullifier() -> Quoted {\n let compute_note_hash = generate_contract_library_method_compute_note_hash();\n let compute_note_nullifier = generate_contract_library_method_compute_note_nullifier();\n\n quote {\n $compute_note_hash\n $compute_note_nullifier\n\n /// Unpacks an array into a note corresponding to `note_type_id` and then computes its note hash (non-siloed) and inner nullifier (non-siloed) assuming the note has been inserted into the note hash tree with `note_nonce`.\n ///\n /// This function is automatically injected by the `#[aztec]` macro.\n #[contract_library_method]\n #[allow(dead_code)]\n unconstrained fn _compute_note_hash_and_nullifier(\n packed_note: BoundedVec<Field, aztec::messages::logs::note::MAX_NOTE_PACKED_LEN>,\n owner: aztec::protocol::address::AztecAddress,\n storage_slot: Field,\n note_type_id: Field,\n contract_address: aztec::protocol::address::AztecAddress,\n randomness: Field,\n note_nonce: Field,\n ) -> Option<aztec::messages::discovery::NoteHashAndNullifier> {\n _compute_note_hash(packed_note, owner, storage_slot, note_type_id, contract_address, randomness).map(|note_hash| {\n\n let siloed_note_hash = aztec::protocol::hash::compute_siloed_note_hash(contract_address, note_hash);\n let unique_note_hash = aztec::protocol::hash::compute_unique_note_hash(note_nonce, siloed_note_hash);\n \n let inner_nullifier = _compute_note_nullifier(unique_note_hash, packed_note, owner, storage_slot, note_type_id, contract_address, randomness);\n\n aztec::messages::discovery::NoteHashAndNullifier {\n note_hash,\n inner_nullifier,\n }\n })\n }\n }\n}\n\ncomptime fn generate_contract_library_method_compute_note_hash() -> Quoted {\n if NOTES.len() == 0 {\n // Contracts with no notes still implement this function to avoid having special-casing, the implementation\n // simply throws immediately.\n quote {\n /// This contract does not use private notes, so this function should never be called as it will unconditionally fail.\n ///\n /// This function is automatically injected by the `#[aztec]` macro.\n #[contract_library_method]\n unconstrained fn _compute_note_hash(\n _packed_note: BoundedVec<Field, aztec::messages::logs::note::MAX_NOTE_PACKED_LEN>,\n _owner: aztec::protocol::address::AztecAddress,\n _storage_slot: Field,\n _note_type_id: Field,\n _contract_address: aztec::protocol::address::AztecAddress,\n _randomness: Field,\n ) -> Option<Field> {\n panic(f\"This contract does not use private notes\")\n }\n }\n } else {\n // Contracts that do define notes produce an if-else chain where `note_type_id` is matched against the\n // `get_note_type_id()` function of each note type that we know of, in order to identify the note type. Once we\n // know it we call the correct `unpack` method from the `Packable` trait to obtain the underlying\n // note type, and compute the note hash (non-siloed).\n\n // We resolve the log format calls here so that the resulting Quoted values can be spliced into the quote\n // block below.\n let warn_length_mismatch = logging::aztecnr_warn_log_format(\n \"Packed note length mismatch for note type id {0}: expected {1} fields, got {2}. Skipping note.\",\n );\n let warn_unknown_note_type = logging::aztecnr_warn_log_format(\"Unknown note type id {0}. Skipping note.\");\n\n let mut if_note_type_id_match_statements_list = @[];\n for i in 0..NOTES.len() {\n let typ = NOTES.get(i);\n\n let get_note_type_id = get_trait_impl_method(\n typ,\n quote { crate::note::note_interface::NoteType },\n quote { get_id },\n );\n let unpack = get_trait_impl_method(\n typ,\n quote { crate::protocol::traits::Packable },\n quote { unpack },\n );\n\n let compute_note_hash = get_trait_impl_method(\n typ,\n quote { crate::note::note_interface::NoteHash },\n quote { compute_note_hash },\n );\n\n let if_or_else_if = if i == 0 {\n quote { if }\n } else {\n quote { else if }\n };\n\n if_note_type_id_match_statements_list = if_note_type_id_match_statements_list.push_back(\n quote {\n $if_or_else_if note_type_id == $get_note_type_id() {\n // As an extra safety check we make sure that the packed_note BoundedVec has the expected\n // length, since we're about to interpret its raw storage as a fixed-size array by calling the\n // unpack function on it.\n let expected_len = <$typ as $crate::protocol::traits::Packable>::N;\n let actual_len = packed_note.len();\n if actual_len != expected_len {\n $warn_length_mismatch([note_type_id, expected_len as Field, actual_len as Field]);\n Option::none()\n } else {\n let note = $unpack(aztec::utils::array::subarray(packed_note.storage(), 0));\n\n Option::some($compute_note_hash(note, owner, storage_slot, randomness))\n }\n }\n },\n );\n }\n\n let if_note_type_id_match_statements = if_note_type_id_match_statements_list.join(quote {});\n\n quote {\n /// Unpacks an array into a note corresponding to `note_type_id` and then computes its note hash (non-siloed).\n ///\n /// The signature of this function notably matches the `aztec::messages::discovery::ComputeNoteHash` type, and so it can be used to call functions from that module such as `do_sync_state` and `attempt_note_discovery`.\n ///\n /// This function is automatically injected by the `#[aztec]` macro.\n #[contract_library_method]\n unconstrained fn _compute_note_hash(\n packed_note: BoundedVec<Field, aztec::messages::logs::note::MAX_NOTE_PACKED_LEN>,\n owner: aztec::protocol::address::AztecAddress,\n storage_slot: Field,\n note_type_id: Field,\n _contract_address: aztec::protocol::address::AztecAddress,\n randomness: Field,\n ) -> Option<Field> {\n $if_note_type_id_match_statements\n else {\n $warn_unknown_note_type([note_type_id]);\n Option::none()\n }\n }\n }\n }\n}\n\ncomptime fn generate_contract_library_method_compute_note_nullifier() -> Quoted {\n if NOTES.len() == 0 {\n // Contracts with no notes still implement this function to avoid having special-casing, the implementation\n // simply throws immediately.\n quote {\n /// This contract does not use private notes, so this function should never be called as it will unconditionally fail.\n ///\n /// This function is automatically injected by the `#[aztec]` macro.\n #[contract_library_method]\n unconstrained fn _compute_note_nullifier(\n _unique_note_hash: Field,\n _packed_note: BoundedVec<Field, aztec::messages::logs::note::MAX_NOTE_PACKED_LEN>,\n _owner: aztec::protocol::address::AztecAddress,\n _storage_slot: Field,\n _note_type_id: Field,\n _contract_address: aztec::protocol::address::AztecAddress,\n _randomness: Field,\n ) -> Option<Field> {\n panic(f\"This contract does not use private notes\")\n }\n }\n } else {\n // Contracts that do define notes produce an if-else chain where `note_type_id` is matched against the\n // `get_note_type_id()` function of each note type that we know of, in order to identify the note type. Once we\n // know it we call the correct `unpack` method from the `Packable` trait to obtain the underlying\n // note type, and compute the inner nullifier (non-siloed).\n\n // We resolve the log format calls here so that the resulting Quoted values can be spliced into the quote\n // block below.\n let warn_length_mismatch = logging::aztecnr_warn_log_format(\n \"Packed note length mismatch for note type id {0}: expected {1} fields, got {2}. Skipping note.\",\n );\n let warn_unknown_note_type = logging::aztecnr_warn_log_format(\"Unknown note type id {0}. Skipping note.\");\n\n let mut if_note_type_id_match_statements_list = @[];\n for i in 0..NOTES.len() {\n let typ = NOTES.get(i);\n\n let get_note_type_id = get_trait_impl_method(\n typ,\n quote { crate::note::note_interface::NoteType },\n quote { get_id },\n );\n let unpack = get_trait_impl_method(\n typ,\n quote { crate::protocol::traits::Packable },\n quote { unpack },\n );\n\n let compute_nullifier_unconstrained = get_trait_impl_method(\n typ,\n quote { crate::note::note_interface::NoteHash },\n quote { compute_nullifier_unconstrained },\n );\n\n let if_or_else_if = if i == 0 {\n quote { if }\n } else {\n quote { else if }\n };\n\n if_note_type_id_match_statements_list = if_note_type_id_match_statements_list.push_back(\n quote {\n $if_or_else_if note_type_id == $get_note_type_id() {\n // As an extra safety check we make sure that the packed_note BoundedVec has the expected\n // length, since we're about to interpret its raw storage as a fixed-size array by calling the\n // unpack function on it.\n let expected_len = <$typ as $crate::protocol::traits::Packable>::N;\n let actual_len = packed_note.len();\n if actual_len != expected_len {\n $warn_length_mismatch([note_type_id, expected_len as Field, actual_len as Field]);\n Option::none()\n } else {\n let note = $unpack(aztec::utils::array::subarray(packed_note.storage(), 0));\n\n // The message discovery process finds settled notes, that is, notes that were created in\n // prior transactions and are therefore already part of the note hash tree. The note hash\n // for nullification is hence the unique note hash.\n $compute_nullifier_unconstrained(note, owner, unique_note_hash)\n }\n }\n },\n );\n }\n\n let if_note_type_id_match_statements = if_note_type_id_match_statements_list.join(quote {});\n\n quote {\n /// Computes a note's inner nullifier (non-siloed) given its unique note hash, preimage and extra data.\n ///\n /// The signature of this function notably matches the `aztec::messages::discovery::ComputeNoteNullifier` type, and so it can be used to call functions from that module such as `do_sync_state` and `attempt_note_discovery`.\n ///\n /// This function is automatically injected by the `#[aztec]` macro.\n #[contract_library_method]\n unconstrained fn _compute_note_nullifier(\n unique_note_hash: Field,\n packed_note: BoundedVec<Field, aztec::messages::logs::note::MAX_NOTE_PACKED_LEN>,\n owner: aztec::protocol::address::AztecAddress,\n _storage_slot: Field,\n note_type_id: Field,\n _contract_address: aztec::protocol::address::AztecAddress,\n _randomness: Field,\n ) -> Option<Field> {\n $if_note_type_id_match_statements\n else {\n $warn_unknown_note_type([note_type_id]);\n Option::none()\n }\n }\n }\n }\n}\n"
7761
7733
  }
7762
7734
  }
7763
7735
  }