diff --git a/dpos.log b/dpos.log index 7ee4172..328447e 100644 --- a/dpos.log +++ b/dpos.log @@ -1,864 +1,17 @@ http://0.0.0.0:36010/ -116.136.20.120:19642 - - [03/Jul/2019 16:33:02] "HTTP/1.1 GET /update" - 200 OK -116.136.20.120:19642 - - [03/Jul/2019 16:33:57] "HTTP/1.1 GET /" - 200 OK -116.136.20.120:19742 - - [03/Jul/2019 16:40:45] "HTTP/1.1 GET /update" - 200 OK -116.136.20.120:19742 - - [03/Jul/2019 16:41:22] "HTTP/1.1 GET /" - 200 OK -116.136.20.120:19813 - - [03/Jul/2019 16:49:31] "HTTP/1.1 GET /update" - 200 OK -116.136.20.120:19814 - - [03/Jul/2019 16:49:31] "HTTP/1.1 GET /update" - 200 OK -116.136.20.120:19819 - - [03/Jul/2019 16:50:06] "HTTP/1.1 GET /update" - 200 OK -116.136.20.120:19850 - - [03/Jul/2019 16:51:10] "HTTP/1.1 GET /update" - 200 OK -116.136.20.120:19850 - - [03/Jul/2019 16:51:47] "HTTP/1.1 GET /" - 200 OK -116.136.20.120:20756 - - [03/Jul/2019 18:12:00] "HTTP/1.1 GET /update" - 200 OK -116.136.20.120:20756 - - [03/Jul/2019 18:12:37] "HTTP/1.1 GET /" - 200 OK -Traceback (most recent call last): - File "/usr/lib64/python2.7/site-packages/web/application.py", line 239, in process - return self.handle() - File "/usr/lib64/python2.7/site-packages/web/application.py", line 230, in handle - return self._delegate(fn, self.fvars, args) - File "/usr/lib64/python2.7/site-packages/web/application.py", line 462, in _delegate - return handle_class(cls) - File "/usr/lib64/python2.7/site-packages/web/application.py", line 438, in handle_class - return tocall(*args) - File "/root/bumo-test/dpos.py", line 24, in GET - res, msg = data_update(db_file, url='http://127.0.0.1:36012/') - File "/root/bumo-test/model/dpos_data.py", line 112, in data_update - res, data = data_get(url) - File "/root/bumo-test/model/dpos_data.py", line 25, in data_get - res = ca.req('getAccount', payload) - File "/root/bumo-test/model/dpos_test.py", line 84, in req - r = requests.get(self.url + module, params=payload) - File "/usr/lib/python2.7/site-packages/requests/api.py", line 68, in get - return request('get', url, **kwargs) - File "/usr/lib/python2.7/site-packages/requests/api.py", line 50, in request - response = session.request(method=method, url=url, **kwargs) - File "/usr/lib/python2.7/site-packages/requests/sessions.py", line 464, in request - resp = self.send(prep, **send_kwargs) - File "/usr/lib/python2.7/site-packages/requests/sessions.py", line 576, in send - r = adapter.send(request, **kwargs) - File "/usr/lib/python2.7/site-packages/requests/adapters.py", line 415, in send - raise ConnectionError(err, request=request) -ConnectionError: ('Connection aborted.', error(111, 'Connection refused')) - -116.136.20.120:27547 - - [04/Jul/2019 09:29:47] "HTTP/1.1 GET /" - 500 Internal Server Error -ransferred done -2019-07-03 16:48:52 - ./dpos_test.py:[line:730] - INFO: Wait pledge coin transferred done -2019-07-03 16:48:53 - ./dpos_test.py:[line:730] - INFO: Wait pledge coin transferred done -2019-07-03 16:48:54 - ./dpos_test.py:[line:730] - INFO: Wait pledge coin transferred done -2019-07-03 16:48:55 - ./dpos_test.py:[line:730] - INFO: Wait pledge coin transferred done -2019-07-03 16:48:56 - ./dpos_test.py:[line:730] - INFO: Wait pledge coin transferred done -2019-07-03 16:48:57 - ./dpos_test.py:[line:342] - INFO: { - "success_count": 1, - "results": [ - { - "error_desc": "", - "hash": "a65afa111338ff4924168da91e3e61b6bcb436c9e8fa7155e1362d52ca2f1958", - "error_code": 0 - } - ] -} -2019-07-03 16:48:57 - ./dpos_test.py:[line:598] - WARNING: apply execute take 6.05560803413 seconds -2019-07-03 16:48:57 - ./dpos_test.py:[line:1166] - INFO: Wait for proposal done -2019-07-03 16:48:58 - ./dpos_test.py:[line:1166] - INFO: Wait for proposal done -2019-07-03 16:48:59 - ./dpos_test.py:[line:1166] - INFO: Wait for proposal done -2019-07-03 16:49:00 - ./dpos_test.py:[line:1166] - INFO: Wait for proposal done -2019-07-03 16:49:01 - ./dpos_test.py:[line:1166] - INFO: Wait for proposal done -2019-07-03 16:49:02 - ./dpos_test.py:[line:1166] - INFO: Wait for proposal done -2019-07-03 16:49:03 - ./dpos_test.py:[line:1166] - INFO: Wait for proposal done -2019-07-03 16:49:04 - ./dpos_test.py:[line:1166] - INFO: Wait for proposal done -2019-07-03 16:49:05 - ./dpos_test.py:[line:1166] - INFO: Wait for proposal done -2019-07-03 16:49:06 - ./dpos_test.py:[line:1166] - INFO: Wait for proposal done -2019-07-03 16:49:07 - ./dpos_test.py:[line:342] - INFO: { - "success_count": 3, - "results": [ - { - "error_desc": "", - "hash": "db57b4bd2ea917490c5ddc43349eae37d2e810e5ca9e6d9ef9846615801ad24f", - "error_code": 0 - }, - { - "error_desc": "", - "hash": "301803a81da1222ad56b3b482af1bf466a5b8d97682f77c59182578f5d9f46f9", - "error_code": 0 - }, - { - "error_desc": "", - "hash": "338512b75e13261a3bd3056b9ac2d8fc9f4f5a17f18663fc063a8b41e2c44645", - "error_code": 0 - } - ] -} -2019-07-03 17:36:06 - ./dpos_test.py:[line:342] - INFO: { - "success_count": 1, - "results": [ - { - "error_desc": "", - "hash": "13e7d6f0808dba7e9b0c11cc1411e70784e69dbe5b2e117b6b46ee3c1f279083", - "error_code": 0 - } - ] -} -2019-07-03 17:36:38 - ./dpos_test.py:[line:342] - INFO: { - "success_count": 2, - "results": [ - { - "error_desc": "", - "hash": "aa4ac65c2c3759098e1d6e57883a1ca8196974ba8cd8c026553cd5dcf1023f1f", - "error_code": 0 - }, - { - "error_desc": "", - "hash": "92ffbe5289c85e2930edeb9dcba9d829418ffb71a8bba38b4c2560d6454db9fe", - "error_code": 0 - } - ] -} -2019-07-03 17:37:08 - ./dpos_test.py:[line:342] - INFO: { - "success_count": 1, - "results": [ - { - "error_desc": "", - "hash": "9210eb052f4bdd5f02cf2aa1af55822ae2bfb7f861816f36304367b616170f91", - "error_code": 0 - } - ] -} -2019-07-03 17:37:40 - ./dpos_test.py:[line:342] - INFO: { - "success_count": 2, - "results": [ - { - "error_desc": "", - "hash": "b9b92b236c1984f562464a8590aae1e8043c170bf540e47883478b7db316f0c9", - "error_code": 0 - }, - { - "error_desc": "", - "hash": "e9a9c487ca856c83b67080e0b93a61cb2c88cee5a3b3f570628ca5c0b760fecc", - "error_code": 0 - } - ] -} -2019-07-03 17:38:10 - ./dpos_test.py:[line:342] - INFO: { - "success_count": 1, - "results": [ - { - "error_desc": "", - "hash": "091b57ed6d9e9f79a5072c9d8cb0a0d08ca17e329adac2735dcf6ff08d1e34ad", - "error_code": 0 - } - ] -} -2019-07-03 17:38:42 - ./dpos_test.py:[line:342] - INFO: { - "success_count": 2, - "results": [ - { - "error_desc": "", - "hash": "c7d9c87457ad37e3e5f7bb947dc0383e4716c027dd0b0f9999425fd64595a7b8", - "error_code": 0 - }, - { - "error_desc": "", - "hash": "ad45a2eb025bf9d98d9b09927ba2a1aea732e07b755c3d92225268d89b9d3f70", - "error_code": 0 - } - ] -} -2019-07-03 17:39:12 - ./dpos_test.py:[line:342] - INFO: { - "success_count": 1, - "results": [ - { - "error_desc": "", - "hash": "abad209c1317437df40c73e76839373100e78dff77d80dcdbf58ec7e7aef4dd8", - "error_code": 0 - } - ] -} -2019-07-03 17:39:44 - ./dpos_test.py:[line:342] - INFO: { - "success_count": 2, - "results": [ - { - "error_desc": "", - "hash": "74899dfd79f22c5ca1a8e608feac2277c41fa255b13912d742df417a97f76856", - "error_code": 0 - }, - { - "error_desc": "", - "hash": "401586a775ccfc95f62ca59ba98cffb56bec4f12507a5059bbb8d3f61dce9b9a", - "error_code": 0 - } - ] -} -2019-07-03 17:40:15 - ./dpos_test.py:[line:342] - INFO: { - "success_count": 1, - "results": [ - { - "error_desc": "", - "hash": "dd81d1697d84ad58787b85e55c5f9baca6235f3bfb9020fd7fad88ca3d95d187", - "error_code": 0 - } - ] -} -2019-07-03 17:40:47 - ./dpos_test.py:[line:342] - INFO: { - "success_count": 2, - "results": [ - { - "error_desc": "", - "hash": "d7704827a0da76ecc0d1cb5c6364e7334b632a4b7e0fbb9cc333294be5fa4b3d", - "error_code": 0 - }, - { - "error_desc": "", - "hash": "53c3c621943d0945e086f1acc06a1070052dd61a30a0886d0a05b107ee1a892d", - "error_code": 0 - } - ] -} -2019-07-03 17:41:17 - ./dpos_test.py:[line:342] - INFO: { - "success_count": 1, - "results": [ - { - "error_desc": "", - "hash": "3d9605338d756401ff96d4f9927fc388afe5163f8aeaaa581ce2f6e5aa81c683", - "error_code": 0 - } - ] -} -2019-07-03 17:41:49 - ./dpos_test.py:[line:342] - INFO: { - "success_count": 2, - "results": [ - { - "error_desc": "", - "hash": "2967be5167b7f6b3355b1852aaddf8380beb9eab46a88f8f3d5caada461ca97d", - "error_code": 0 - }, - { - "error_desc": "", - "hash": "94179aa65a1b6f593b92e91d0869c3108674deaf435802fe56daf303c274595b", - "error_code": 0 - } - ] -} -2019-07-03 17:42:19 - ./dpos_test.py:[line:342] - INFO: { - "success_count": 1, - "results": [ - { - "error_desc": "", - "hash": "ee3fca0eb9f8fe48599bc209d02bfa602b27d1f7fb746aa1a454abdfa1fe960d", - "error_code": 0 - } - ] -} -2019-07-03 17:42:51 - ./dpos_test.py:[line:342] - INFO: { - "success_count": 2, - "results": [ - { - "error_desc": "", - "hash": "af0f4ef0b0aa9ff4614a190b8882e8898fcd9f49a60c517a4f797ccc0501396e", - "error_code": 0 - }, - { - "error_desc": "", - "hash": "7738262900b70def63c015a185b89cbdbe96408f11b45119b8306711767bebd0", - "error_code": 0 - } - ] -} -2019-07-03 17:43:21 - ./dpos_test.py:[line:342] - INFO: { - "success_count": 1, - "results": [ - { - "error_desc": "", - "hash": "bef4cadf26db9d155a3f8560b9c44b1593350c04d5761ddb4dcfabcc2c9f93a4", - "error_code": 0 - } - ] -} -2019-07-03 17:43:53 - ./dpos_test.py:[line:342] - INFO: { - "success_count": 2, - "results": [ - { - "error_desc": "", - "hash": "9fccd68ec653d517008cd9d6ebfc2d234d37c94865cd2aa6312efb134edd55f4", - "error_code": 0 - }, - { - "error_desc": "", - "hash": "5ead450fb056d360ed083c64af9f7406966c69f503fe011a738ba6ba7c9968c3", - "error_code": 0 - } - ] -} -2019-07-03 17:44:23 - ./dpos_test.py:[line:342] - INFO: { - "success_count": 1, - "results": [ - { - "error_desc": "", - "hash": "0b0f6caba08cade5923e24e1c02e5a4d5fd7021762cbf153d37ec66a7de74097", - "error_code": 0 - } - ] -} -2019-07-03 17:44:55 - ./dpos_test.py:[line:342] - INFO: { - "success_count": 2, - "results": [ - { - "error_desc": "", - "hash": "4c1e506fb2add3a2ccd55a74dd616190e4d106939fb67ed7c58940d331836b52", - "error_code": 0 - }, - { - "error_desc": "", - "hash": "7be7421ac36ba49cbfc27049add6b5de65e66a6396150ec1c166ff007ed5e421", - "error_code": 0 - } - ] -} -2019-07-03 17:45:25 - ./dpos_test.py:[line:342] - INFO: { - "success_count": 1, - "results": [ - { - "error_desc": "", - "hash": "1fc60186146ddceaef977d07a3f16b965a5601a5fc64a352346689afa3e31bdc", - "error_code": 0 - } - ] -} -2019-07-03 17:45:57 - ./dpos_test.py:[line:342] - INFO: { - "success_count": 2, - "results": [ - { - "error_desc": "", - "hash": "f6eb469f56f2f9eb031ea5d5308bee999670dd9481ca690c43ccf77aac1dddff", - "error_code": 0 - }, - { - "error_desc": "", - "hash": "d20e19cc92047ed52661ca998809dd5861b6fbf26db73de1f7eb8d16093c3dc2", - "error_code": 0 - } - ] -} -2019-07-03 17:46:27 - ./dpos_test.py:[line:342] - INFO: { - "success_count": 1, - "results": [ - { - "error_desc": "", - "hash": "ee0a2af5ca0abae6a8c84f4dd63a198e8341879c768c9384edc572b3be331654", - "error_code": 0 - } - ] -} -2019-07-03 17:46:59 - ./dpos_test.py:[line:342] - INFO: { - "success_count": 2, - "results": [ - { - "error_desc": "", - "hash": "670d9673df92e525004edd5e7e0367c69dd6f0ea39b54d2c3f563e0ac39562a4", - "error_code": 0 - }, - { - "error_desc": "", - "hash": "a5e3dfec2791c04e361620a1e78d7502323fc990aaa4481acaa2c189de2570dd", - "error_code": 0 - } - ] -} -2019-07-03 17:47:30 - ./dpos_test.py:[line:342] - INFO: { - "success_count": 1, - "results": [ - { - "error_desc": "", - "hash": "d7d8f46712e34671baf74f5d20de66d1f0efb37aae25748852c80862eabf10c0", - "error_code": 0 - } - ] -} -2019-07-03 17:48:02 - ./dpos_test.py:[line:342] - INFO: { - "success_count": 2, - "results": [ - { - "error_desc": "", - "hash": "0ec569b0fac550d0d7c2270ae79f98ed3a306feeac67173979e869c81694e25d", - "error_code": 0 - }, - { - "error_desc": "", - "hash": "c38ad8fef38d1d8566d08fbae274a57c8d61afd8da7b75b3bbb300992fa4aafb", - "error_code": 0 - } - ] -} -2019-07-03 17:48:32 - ./dpos_test.py:[line:342] - INFO: { - "success_count": 1, - "results": [ - { - "error_desc": "", - "hash": "c3dbc55a25f59462cfc91d56d4e9d56faecc13be8c3edc1efb7819c79627267e", - "error_code": 0 - } - ] -} -2019-07-03 17:49:04 - ./dpos_test.py:[line:342] - INFO: { - "success_count": 2, - "results": [ - { - "error_desc": "", - "hash": "b131446c28132de334e75d950feacc5b180dfd4ad7c6795c814fef47d7e4a78a", - "error_code": 0 - }, - { - "error_desc": "", - "hash": "010d18441105e1b66e31ce5a754ddc8f263b9b14c3f8b2f462a7a1e45f1f2878", - "error_code": 0 - } - ] -} -2019-07-03 17:49:34 - ./dpos_test.py:[line:342] - INFO: { - "success_count": 1, - "results": [ - { - "error_desc": "", - "hash": "0672aeeb94a0ba1d651c565a71fe8e1811e7d544f652948dea3b165475970820", - "error_code": 0 - } - ] -} -2019-07-03 17:50:06 - ./dpos_test.py:[line:342] - INFO: { - "success_count": 2, - "results": [ - { - "error_desc": "", - "hash": "b5d1a7d70137a8de9d483b0ec6ec4cc4778e049a57c31636020bdfcb48dc89ca", - "error_code": 0 - }, - { - "error_desc": "", - "hash": "8e9490b026ca7ac1bd94e76b4bb27457c2be5456a1879aff8111eaebcdbaa028", - "error_code": 0 - } - ] -} -2019-07-03 17:50:36 - ./dpos_test.py:[line:342] - INFO: { - "success_count": 1, - "results": [ - { - "error_desc": "", - "hash": "c7a40fbd8e372511345f894aaa8889a17c4ad4d95256e2a25433f7bcb30a4bfc", - "error_code": 0 - } - ] -} -2019-07-03 17:51:08 - ./dpos_test.py:[line:342] - INFO: { - "success_count": 2, - "results": [ - { - "error_desc": "", - "hash": "469f8dd78948c8c53bc0e79b69a4ade711579fd95d8a0c6b822fc424ecfdab3b", - "error_code": 0 - }, - { - "error_desc": "", - "hash": "72dea4543f47b678c6a5db2e844a8a35ac3231ff09a0e5dfccef3d095becbcc7", - "error_code": 0 - } - ] -} -2019-07-03 17:51:38 - ./dpos_test.py:[line:342] - INFO: { - "success_count": 1, - "results": [ - { - "error_desc": "", - "hash": "32c3c44cc69c61d3cb168bb67814e9587df4d3c4ad010113d8629f947e42379d", - "error_code": 0 - } - ] -} -2019-07-03 17:52:10 - ./dpos_test.py:[line:342] - INFO: { - "success_count": 2, - "results": [ - { - "error_desc": "", - "hash": "c9b36128122eeda5aa99432dc44e9cbbac9a88f8bef8c9507bb6c4cca334f373", - "error_code": 0 - }, - { - "error_desc": "", - "hash": "6edc7a9d470cae03f2c501bdba9c5261d601fff827b386e9f94cef3a2a0cc22a", - "error_code": 0 - } - ] -} -2019-07-03 17:52:40 - ./dpos_test.py:[line:342] - INFO: { - "success_count": 1, - "results": [ - { - "error_desc": "", - "hash": "d91336557cdc5ce65b1a8246cd167e28f5e6c4ab195225b98b684471f1a0f286", - "error_code": 0 - } - ] -} -2019-07-03 17:53:12 - ./dpos_test.py:[line:342] - INFO: { - "success_count": 2, - "results": [ - { - "error_desc": "", - "hash": "b5c863b516c11cb45a22f9325d6503d7e1e874edb944e587677f2cff549ea1c1", - "error_code": 0 - }, - { - "error_desc": "", - "hash": "d7fc98bbf9315dd705594b6479c86408c1f1fb407f8c323d9558418236188ca5", - "error_code": 0 - } - ] -} -2019-07-03 17:53:42 - ./dpos_test.py:[line:342] - INFO: { - "success_count": 1, - "results": [ - { - "error_desc": "", - "hash": "33062f4c1a82da349afd9d77216688d4b0c6c5cd352d7e3ebbc2b0f0fca87995", - "error_code": 0 - } - ] -} -2019-07-03 17:54:14 - ./dpos_test.py:[line:342] - INFO: { - "success_count": 2, - "results": [ - { - "error_desc": "", - "hash": "c525365409b833fd2aabf7ababc3cc4f7b38c37f147a449bd877bb4172e25b92", - "error_code": 0 - }, - { - "error_desc": "", - "hash": "1a09d409b8a04de88ca311124ca0b9c3c94c4f123efb7f76ffa3b647c6c0ff66", - "error_code": 0 - } - ] -} -2019-07-03 17:54:45 - ./dpos_test.py:[line:342] - INFO: { - "success_count": 1, - "results": [ - { - "error_desc": "", - "hash": "d38bbb75c09b12800821d8c4cab9ee7c5e7cbb27691eb53f3d072b8ebc0db6b7", - "error_code": 0 - } - ] -} -2019-07-03 17:55:17 - ./dpos_test.py:[line:342] - INFO: { - "success_count": 2, - "results": [ - { - "error_desc": "", - "hash": "2f732ce7503820d9ba4566d3b25cf1fafcf9e3bc4f0958a8e02c3546fb9282b3", - "error_code": 0 - }, - { - "error_desc": "", - "hash": "181b6d4b03fed653595719f4a202dbda14cbd74c51e5f74457c6978287f52262", - "error_code": 0 - } - ] -} -2019-07-03 17:55:47 - ./dpos_test.py:[line:342] - INFO: { - "success_count": 1, - "results": [ - { - "error_desc": "", - "hash": "e11c206133af03c7eecd9e2a1cc51ea91315e9e0dd063852a1e08c9ef53b6d18", - "error_code": 0 - } - ] -} -2019-07-03 17:56:19 - ./dpos_test.py:[line:342] - INFO: { - "success_count": 2, - "results": [ - { - "error_desc": "", - "hash": "65045d49029659b6793691fada219e9984eae7e3ce328e451ad5d2cd1e1da517", - "error_code": 0 - }, - { - "error_desc": "", - "hash": "384d18a5e19aa64c04ceacd99f2dc6ff4d985c33434a71c83d84e7dde016c472", - "error_code": 0 - } - ] -} -2019-07-03 17:56:49 - ./dpos_test.py:[line:342] - INFO: { - "success_count": 1, - "results": [ - { - "error_desc": "", - "hash": "f4c30d0f4f7fe584a73da061b457210ddca0f9e6604c09cf32c1e40e1520df88", - "error_code": 0 - } - ] -} -2019-07-03 17:57:21 - ./dpos_test.py:[line:342] - INFO: { - "success_count": 2, - "results": [ - { - "error_desc": "", - "hash": "a4a6fac6ee6a554bac862c2614c376cac0a439071896932938635b50eca6b6b0", - "error_code": 0 - }, - { - "error_desc": "", - "hash": "af005978d58685696dd8bb785173a85877989518c112ea6a2219c9fe09726b23", - "error_code": 0 - } - ] -} -2019-07-03 17:57:51 - ./dpos_test.py:[line:342] - INFO: { - "success_count": 1, - "results": [ - { - "error_desc": "", - "hash": "741d88a9c14568927ba35bdf951aabf2c075e8f7bf312fcab6204da9ae13e22d", - "error_code": 0 - } - ] -} -2019-07-03 17:58:23 - ./dpos_test.py:[line:342] - INFO: { - "success_count": 2, - "results": [ - { - "error_desc": "", - "hash": "37052fd06342935070debb5e1e8763dd4e36836e6834d7445305827504f1eb9f", - "error_code": 0 - }, - { - "error_desc": "", - "hash": "a11a66d1a0192008725eaab442e0b74deb72cd12b1fe21cb3add4d2b95f3fe18", - "error_code": 0 - } - ] -} -2019-07-03 17:58:53 - ./dpos_test.py:[line:342] - INFO: { - "success_count": 1, - "results": [ - { - "error_desc": "", - "hash": "1f2a3f5e2696df2a1a1c50c06a1587b45717804d19164bcf609f988e8c785216", - "error_code": 0 - } - ] -} -2019-07-03 17:59:25 - ./dpos_test.py:[line:342] - INFO: { - "success_count": 2, - "results": [ - { - "error_desc": "", - "hash": "2778b9f02dd13e95416ddcf3d22f22e5dc06e76279a95f3105b9aa53661511e4", - "error_code": 0 - }, - { - "error_desc": "", - "hash": "30bd282ecb1c1f5248bf11b39dc21b8c6b90aa0e5ced2102ee12121493b10e30", - "error_code": 0 - } - ] -} -2019-07-03 17:59:55 - ./dpos_test.py:[line:342] - INFO: { - "success_count": 1, - "results": [ - { - "error_desc": "", - "hash": "95f89e0d3133c13c58bde3430d48dc9a568c7aaaa719d9996d1b35ca341df4f0", - "error_code": 0 - } - ] -} -2019-07-03 18:00:27 - ./dpos_test.py:[line:342] - INFO: { - "success_count": 2, - "results": [ - { - "error_desc": "", - "hash": "79acb448eca55bfcb8b7b5874ec94af5a57682ea9aea9df9bfe1fd9505766434", - "error_code": 0 - }, - { - "error_desc": "", - "hash": "711df23dfe0b85f9a567d34795480fe85c9bab7a3e45d9f00c9c761d9ec89035", - "error_code": 0 - } - ] -} -2019-07-03 18:00:57 - ./dpos_test.py:[line:342] - INFO: { - "success_count": 1, - "results": [ - { - "error_desc": "", - "hash": "a23485fa11d0eff048c674a0b4e5308eec50abde78032cd088ea30609e5ea2bd", - "error_code": 0 - } - ] -} -2019-07-03 18:01:29 - ./dpos_test.py:[line:342] - INFO: { - "success_count": 2, - "results": [ - { - "error_desc": "", - "hash": "f005f50824c1ae15fd5cf3fb482a701ae5767a6964559d6f9dcf1d3ea51c29cc", - "error_code": 0 - }, - { - "error_desc": "", - "hash": "7db4821eaa9c3ee7e4f0750f3206f62a8a2fa9fb1ae9bbebf26bbd6d1f1911e3", - "error_code": 0 - } - ] -} -2019-07-03 18:02:00 - ./dpos_test.py:[line:342] - INFO: { - "success_count": 1, - "results": [ - { - "error_desc": "", - "hash": "24fdd2354afa4bda476d1dbb1a1bd44c3d6deff366c803e97e8d42026c5308b8", - "error_code": 0 - } - ] -} -2019-07-03 18:02:32 - ./dpos_test.py:[line:342] - INFO: { - "success_count": 2, - "results": [ - { - "error_desc": "", - "hash": "6f014f82d28bac2072a8f75135b6d89436aa28ab3ebf91ab8e327d2d5ee820ec", - "error_code": 0 - }, - { - "error_desc": "", - "hash": "a525e25e8e43ebee9c0e40d5768b5ee49dd615652ea2398297a42cccfbea9846", - "error_code": 0 - } - ] -} -2019-07-03 18:03:02 - ./dpos_test.py:[line:342] - INFO: { - "success_count": 1, - "results": [ - { - "error_desc": "", - "hash": "cc7846d706d662ad8845ce4ca4f371980f874c97a11280bd8fe40769a836d382", - "error_code": 0 - } - ] -} -2019-07-03 18:03:34 - ./dpos_test.py:[line:342] - INFO: { - "success_count": 2, - "results": [ - { - "error_desc": "", - "hash": "309745957b9b9cadeaf3626583061f571d4fca41ddd006a0f0d48650a8ec2c9e", - "error_code": 0 - }, - { - "error_desc": "", - "hash": "9bca6e9f4c6b43420dc2f72cab7da895e4b18b75d5827e187c5016c55b1f59ab", - "error_code": 0 - } - ] -} -2019-07-03 18:04:04 - ./dpos_test.py:[line:342] - INFO: { - "success_count": 1, - "results": [ - { - "error_desc": "", - "hash": "9a3990c6544b7240c75b85ee8af484f6598d1c025c57d6243734d7db4469d061", - "error_code": 0 - } - ] -} -2019-07-03 18:04:36 - ./dpos_test.py:[line:342] - INFO: { - "success_count": 2, - "results": [ - { - "error_desc": "", - "hash": "6a3949d21c2233ffdd96247de00a9be4cb2d58cde1c337a82caf38fffce93d98", - "error_code": 0 - }, - { - "error_desc": "", - "hash": "673c2d06c6986c1fea6f6a5360fbb75277376931346f7c865a8e2560b130d410", - "error_code": 0 - } - ] -} -2019-07-03 18:05:06 - ./dpos_test.py:[line:342] - INFO: { - "success_count": 1, - "results": [ - { - "error_desc": "", - "hash": "b12ae97b9a3f868a65a0b5f1cbe4e6541b837df3e28f54ad6571a67659a77d2c", - "error_code": 0 - } - ] -} -2019-07-03 18:05:38 - ./dpos_test.py:[line:342] - INFO: { - "success_count": 2, - "results": [ - { - "error_desc": "", - "hash": "9487ef7bdc8a5294107dc98ce0762d01d6f2d14d7ef4c82b60c5af2b651f1590", - "error_code": 0 - }, - { - "error_desc": "", - "hash": "2ef09b688612e5b70a73ab3fc9a4e6a6afdba6880c56ec5442ea9aa7be89e548", - "error_code": 0 - } - ] -} -2019-07-03 18:06:08 - ./dpos_test.py:[line:342] - INFO: { - "success_count": 1, - "results": [ - { - "error_desc": "", - "hash": "81c2e5440ec0e73dc77ed10c229537a1913e7923a83cc0b34111455e500b9a40", - "error_code": 0 - } - ] -} -2019-07-03 18:06:40 - ./dpos_test.py:[line:342] - INFO: { - "success_count": 2, - "results": [ - { - "error_desc": "", - "hash": "b2dacd738d96fd116b81bf4e6473b4ecbe9c6f7704fa32b7c6b65f3aec82fe70", - "error_code": 0 - }, - { - "error_desc": "", - "hash": "ae75eafc5058c60e1d11d72e6709fe2a74f47fcda7c78b1915fc36718acff377", - "error_code": 0 - } - ] -} -2019-07-03 18:16:30 - ./dpos_test.py:[line:342] - INFO: { - "success_count": 1, - "results": [ - { - "error_desc": "", - "hash": "81c2e5440ec0e73dc77ed10c229537a1913e7923a83cc0b34111455e500b9a40", - "error_code": 0 - } - ] -} -2019-07-03 18:17:02 - ./dpos_test.py:[line:342] - INFO: { - "success_count": 2, - "results": [ - { - "error_desc": "", - "hash": "b2dacd738d96fd116b81bf4e6473b4ecbe9c6f7704fa32b7c6b65f3aec82fe70", - "error_code": 0 - }, - { - "error_desc": "", - "hash": "ae75eafc5058c60e1d11d72e6709fe2a74f47fcda7c78b1915fc36718acff377", - "error_code": 0 - } - ] -} +39.155.215.118:8137 - - [19/Jul/2019 09:57:00] "HTTP/1.1 GET /" - 200 OK +39.155.215.118:4453 - - [22/Jul/2019 12:54:35] "HTTP/1.1 GET /" - 200 OK +39.155.215.118:4453 - - [22/Jul/2019 12:54:35] "HTTP/1.1 GET /favicon.ico" - 404 Not Found +51.158.162.87:4812 - - [22/Jul/2019 17:09:42] "HTTP/1.1 POST /" - 405 Method Not Allowed +67.205.184.153:32766 - - [22/Jul/2019 20:25:42] "HTTP/1.1 POST /" - 405 Method Not Allowed +202.29.57.103:32766 - - [23/Jul/2019 01:13:50] "HTTP/1.1 POST /" - 405 Method Not Allowed +192.241.138.140:32766 - - [23/Jul/2019 10:37:15] "HTTP/1.1 POST /" - 405 Method Not Allowed +51.158.162.87:47022 - - [23/Jul/2019 15:13:38] "HTTP/1.1 POST /" - 405 Method Not Allowed +67.205.184.166:32766 - - [23/Jul/2019 16:08:28] "HTTP/1.1 POST /" - 405 Method Not Allowed +67.205.184.220:32766 - - [23/Jul/2019 23:27:37] "HTTP/1.1 POST /" - 405 Method Not Allowed +202.29.57.103:32766 - - [24/Jul/2019 00:22:56] "HTTP/1.1 POST /" - 405 Method Not Allowed +67.205.184.166:32766 - - [24/Jul/2019 03:38:19] "HTTP/1.1 POST /" - 405 Method Not Allowed +198.199.77.189:32766 - - [24/Jul/2019 08:14:52] "HTTP/1.1 POST /" - 405 Method Not Allowed +39.155.215.118:4351 - - [24/Jul/2019 09:35:56] "HTTP/1.1 GET /" - 200 OK +51.158.162.87:22518 - - [24/Jul/2019 13:16:38] "HTTP/1.1 POST /" - 405 Method Not Allowed +202.29.57.103:32766 - - [24/Jul/2019 13:18:01] "HTTP/1.1 POST /" - 405 Method Not Allowed diff --git a/dpos.py b/dpos.py index 384007f..25441de 100644 --- a/dpos.py +++ b/dpos.py @@ -20,8 +20,8 @@ class index: def GET(self): - #res, msg = data_update(db_file, url='http://seed1.bumo.io:16002/') - res, msg = data_update(db_file, url='http://127.0.0.1:36012/') + res, msg = data_update(db_file, url='http://seed1.bumo.io:16002/') + #res, msg = data_update(db_file, url='http://127.0.0.1:36012/') v_cands=data_read('validator_candidates', db_file) k_cands=data_read('kol_candidates', db_file) committee=data_read('committee', db_file) diff --git a/model/dpos_test.py b/model/dpos_test.py index 23ec86f..649c67f 100755 --- a/model/dpos_test.py +++ b/model/dpos_test.py @@ -18,6 +18,7 @@ base_url = 'http://127.0.0.1:36012/' +#base_url = 'http://seed1.bumo.io:16002/' max_items = 500 # max tx number per http request genesis_account = 'buQs9npaCq9mNFZG18qu88ZcmXYqd6bqpTU3' genesis_priv_key = 'privbvYfqQyG3kZyHE4RX4TYVa32htw8xG4WdpCTrymPUJQ923XkKVbM' @@ -660,7 +661,7 @@ def dposInit(self, update=False): input_str = "{\"method\": \"init\", \"params\": {\"logic_contract\": \"%s\", \"committee\": [\"buQZoJk8bq6A1AtsmfRw3rYJ79eMHUyct9i2\", \"buQYKj4TTJPVDPXCLWeBZMoCr1JPhq9Z2tJm\", \"buQcYkkoZFMwDNQgCD7DoykNZjtax4FjVSzy\", \"buQmKmaeCyGcPk9KbvnkhpLzQa34tQ9MaWwt\"]}}" % logic_addr logger.info('Start create dpos delegate contract') - res = self.createContract(dpos_addr, newNonce(dpos_creator_account['address']), content, input_str, src_account=dpos_creator_account) + res = self.createContract(dpos_addr, self.newNonce(dpos_creator_account['address']), content, input_str, src_account=dpos_creator_account) if debug: logger.info(json.dumps(res, indent=4)) diff --git a/privacy/zsl/.gitignore b/privacy/zsl/.gitignore new file mode 100644 index 0000000..e025c54 --- /dev/null +++ b/privacy/zsl/.gitignore @@ -0,0 +1,2 @@ +*.pk +*.vk diff --git a/privacy/zsl/Makefile b/privacy/zsl/Makefile new file mode 100644 index 0000000..3ccfb46 --- /dev/null +++ b/privacy/zsl/Makefile @@ -0,0 +1,11 @@ +CXXFLAGS = -Wno-unused-parameter -std=c++11 -fPIC -Wno-unused-variable +CXXFLAGS += -L./zsl/snark + +LDLIBS += -lgmpxx -lgmp -lboost_system -fopenmp -lcrypto -lzsl +SUBDIR = ./zsl/snark + +all: + cd $(SUBDIR) && make + g++ main.cpp utils/util.cpp utils/sha256.cpp -o zsltest $(CXXFLAGS) $(LDLIBS) +clean: + rm -f zsltest ./zsl/snark/libsnark.a diff --git a/privacy/zsl/api.hpp b/privacy/zsl/api.hpp new file mode 100644 index 0000000..f9cae88 --- /dev/null +++ b/privacy/zsl/api.hpp @@ -0,0 +1,74 @@ +#ifndef _API_HPP_ +#define _API_HPP_ + +#include +#include +#include + +#include "note.hpp" + + +void computeSendNullifier(unsigned char *rho, unsigned char *send_nf) { + unsigned char data[33]; + data[0] = 0x00; + + for(int i = 0; i < 32; i++) { + data[i+1] = rho[i]; + } + + sha256(data, 33, send_nf); + + return; +} + +void computeSpendNullifier(unsigned char *rho, unsigned char *sk, unsigned char *spend_nf) { + unsigned char data[65]; + data[0] = 0x01; + + for(int i = 0; i < 32; i++) { + data[i+1] = rho[i]; + } + + for(int i = 0; i < 32; i++) { + data[i+33] = sk[i]; + } + + sha256(data, 65, spend_nf); + + return; +} + +void computeCommitment(unsigned char *rho, unsigned char *pk, uint64_t value, unsigned char *commitment) { + unsigned char data[64+sizeof(value)]; + + for(int i = 0; i < 32; i++) { + data[i] = rho[i]; + } + + for(int i = 0; i < 32; i++) { + data[i+32] = pk[i]; + } + + for(int i = 0; i < sizeof(value); i++) { + data[i+64] = (value >> (8 * i)) & 255; // little endian, big endian will use << operator + } + + sha256(data, 64+sizeof(value), commitment); + + return; +} + +/*void CreateShielding(unsigned char *rho, unsigned char *pk, uint64_t value, std::map) { + + return; +} + + +void CreateShieldedTransfer(unsigned char *rho_1, unsigned char *sk_1, uint64_t value_1, uint64_t treeIndex_1, std::vector authPath_1, + unsigned char *rho_2, unsigned char *sk_2, uint64_t value_2, uint64_t treeIndex_1, std::vector authPath_2, + unsigned char *out_rho_1, unsigned char *out_pk_1, uint64_t out_value_1, + unsigned char *out_rho_2, unsigned char *out_pk_2, uint64_t out_value_2) { + return; +}*/ + +#endif diff --git a/privacy/zsl/main.cpp b/privacy/zsl/main.cpp new file mode 100644 index 0000000..e1909e5 --- /dev/null +++ b/privacy/zsl/main.cpp @@ -0,0 +1,247 @@ +#include +#include + +#include "note.hpp" +#include "api.hpp" +#include "zsl/snark/zsl.h" + +unsigned char rho[32]; +unsigned char pk[32]; +unsigned char sk[32]; +uint64_t value = 0; + + +bool shielding() +{ + get_keypair(sk, pk); + + std::cout << "a_pk:"; + print_char_array(pk, 32); + std::cout << "a_sk:"; + print_char_array(sk, 32); + + value = 2378237 ; + get_randomness(rho, 32); + + + // zsl_prove_shielding(void *rho, void *pk, uint64_t value, void *output_proof); + unsigned char proof_str[584]; + zsl_prove_shielding(rho, pk, value, proof_str); + + unsigned char send_nf[32]; + unsigned char cm[32]; + computeSendNullifier(rho, send_nf); + computeCommitment(rho, pk, value, cm); + + bool ret = zsl_verify_shielding(proof_str, send_nf, cm, value); + if(!ret) { + std::cout << "shield verify failed" << std::endl; + } else { + std::cout << "shield verify done" << std::endl; + } + return true; +} + +bool unshileding() +{ + // zsl_prove_unshielding(void *rho, void *sk, uint64_t value, uint64_t tree_position, void *authentication_path, void *output_proof); + std::string rho_str = "dedeffdddedeffdddedeffdddedeffdddedeffdddedeffdddedeffdddedeffdd"; + std::string sk_str = "f0f0f0f00f0f0ffffffffff000000f0f0f0f0f00f0000f0f00f00f0f0f0f00ff"; + /*unsigned char rho[] = {0xde, 0xde, 0xff, 0xdd, 0xde, 0xde, 0xff, 0xdd, 0xde, 0xde, 0xff, 0xdd, 0xde, 0xde, 0xff, 0xdd, 0xde, 0xde, 0xff, 0xdd, 0xde, 0xde, 0xff, 0xdd, 0xde, 0xde, 0xff, 0xdd, 0xde, 0xde, 0xff, 0xdd}; + unsigned char sk[] = {0xf0, 0xf0, 0xf0, 0xf0, 0x0f, 0x0f, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x00, 0xf0, 0x00, 0x0f, 0x0f, 0x00, 0xf0, 0x0f, 0x0f, 0x0f, 0x0f, 0x00, 0xff};*/ + value = 2378237; + + unsigned char rho[32]; + unsigned char sk[32]; + hex_str_to_array(rho_str, rho); + hex_str_to_array(sk_str, sk); + + uint64_t tree_position = 0; + unsigned char path_item[32]; + std::string path_item_str = "8000000000000000000000000000000000000000000000000000000000000100"; + hex_str_to_array(path_item_str, path_item); + + unsigned char auth_path[29][32]; + for (int i = 0; i < 29; i++) { + for (int j = 0; j < 32; j++) { + auth_path[i][j] = path_item[j]; + } + } + + /*unsigned char auth_path[29][32] = { + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}};*/ + unsigned char proof_u[584] = {0x0}; + zsl_prove_unshielding(rho, sk, value, tree_position, auth_path, proof_u); + + unsigned char spend_nf[32]; + unsigned char rt[32]; + std::string spend_nf_str = "45ccb210613318d0d127e9947c2ce6b1b246c5c2dd53489c1f39397843410c1a"; + std::string rt_str = "8610652739ac0c6bb6b5353649bb822b26543f0ebe88f32a489a56843cd04f03"; + hex_str_to_array(spend_nf_str, spend_nf); + hex_str_to_array(rt_str, rt); + //unsigned char spend_nf[] = {0x45, 0xcc, 0xb2, 0x10, 0x61, 0x33, 0x18, 0xd0, 0xd1, 0x27, 0xe9, 0x94, 0x7c, 0x2c, 0xe6, 0xb1, 0xb2, 0x46, 0xc5, 0xc2, 0xdd, 0x53, 0x48, 0x9c, 0x1f, 0x39, 0x39, 0x78, 0x43, 0x41, 0x0c, 0x1a}; + //unsigned char rt[] = {0x86, 0x10, 0x65, 0x27, 0x39, 0xac, 0x0c, 0x6b, 0xb6, 0xb5, 0x35, 0x36, 0x49, 0xbb, 0x82, 0x2b, 0x26, 0x54, 0x3f, 0x0e, 0xbe, 0x88, 0xf3, 0x2a, 0x48, 0x9a, 0x56, 0x84, 0x3c, 0xd0, 0x4f, 0x03}; + bool ret = zsl_verify_unshielding(proof_u, spend_nf, rt, value); + + if(!ret) { + std::cout << "unshield verify failed" << std::endl; + } else { + std::cout << "unshield verify done" << std::endl; + } + return true; +} + +bool shield_transfer() +{ + unsigned char output_proof_ptr[584] = {0x0}; + unsigned char input_rho_ptr_1[] = {0xde, 0xde, 0xff, 0xdd, 0xde, 0xde, 0xff, 0xdd, 0xde, 0xde, 0xff, 0xdd, 0xde, 0xde, 0xff, 0xdd, 0xde, 0xde, 0xff, 0xdd, 0xde, 0xde, 0xff, 0xdd, 0xde, 0xde, 0xff, 0xdd, 0xde, 0xde, 0xff, 0xdd}; + unsigned char input_pk_ptr_1[] = {0xf0, 0xf0, 0xf0, 0xf0, 0x0f, 0x0f, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x00, 0xf0, 0x00, 0x0f, 0x0f, 0x00, 0xf0, 0x0f, 0x0f, 0x0f, 0x0f, 0x00, 0xff}; + uint64_t input_value_1 = 2378237; + uint64_t input_tree_position_1 = 0; + unsigned char input_authentication_path_ptr_1[29][32] = { + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}}; + unsigned char input_rho_ptr_2[] = {0xde, 0xde, 0xff, 0xdd, 0xde, 0xde, 0xff, 0xdd, 0xde, 0xde, 0xff, 0xdd, 0xde, 0xde, 0xff, 0xdd, 0xde, 0xde, 0xff, 0xdd, 0xde, 0xde, 0xff, 0xdd, 0xde, 0xde, 0xff, 0xdd, 0xde, 0xde, 0xff, 0xdd}; + unsigned char input_pk_ptr_2[] = {0xf0, 0xf0, 0xf0, 0xf0, 0x0f, 0x0f, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x00, 0xf0, 0x00, 0x0f, 0x0f, 0x00, 0xf0, 0x0f, 0x0f, 0x0f, 0x0f, 0x00, 0xff}; + uint64_t input_value_2 = 2378237; + uint64_t input_tree_position_2 = 0; + unsigned char input_authentication_path_ptr_2[29][32] = { + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}}; + unsigned char output_rho_ptr_1[] = {0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac}; + unsigned char output_pk_ptr_1[] = {0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb}; + uint64_t output_value_1 = 2378237; + unsigned char output_rho_ptr_2[] = {0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac}; + unsigned char output_pk_ptr_2[] = {0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb}; + uint64_t output_value_2 = 2378237; + + zsl_prove_transfer(output_proof_ptr, input_rho_ptr_1, input_pk_ptr_1, input_value_1, input_tree_position_1, input_authentication_path_ptr_1, input_rho_ptr_2, input_pk_ptr_2, input_value_2, input_tree_position_2, input_authentication_path_ptr_2, output_rho_ptr_1, output_pk_ptr_1, output_value_1, output_rho_ptr_2, output_pk_ptr_2, output_value_2); + + unsigned char anchor_ptr[] = {0x86, 0x10, 0x65, 0x27, 0x39, 0xac, 0x0c, 0x6b, 0xb6, 0xb5, 0x35, 0x36, 0x49, 0xbb, 0x82, 0x2b, 0x26, 0x54, 0x3f, 0x0e, 0xbe, 0x88, 0xf3, 0x2a, 0x48, 0x9a, 0x56, 0x84, 0x3c, 0xd0, 0x4f, 0x03}; + unsigned char spend_nf_ptr_1[] = {0x45, 0xcc, 0xb2, 0x10, 0x61, 0x33, 0x18, 0xd0, 0xd1, 0x27, 0xe9, 0x94, 0x7c, 0x2c, 0xe6, 0xb1, 0xb2, 0x46, 0xc5, 0xc2, 0xdd, 0x53, 0x48, 0x9c, 0x1f, 0x39, 0x39, 0x78, 0x43, 0x41, 0x0c, 0x1a}; + unsigned char spend_nf_ptr_2[] = {0x45, 0xcc, 0xb2, 0x10, 0x61, 0x33, 0x18, 0xd0, 0xd1, 0x27, 0xe9, 0x94, 0x7c, 0x2c, 0xe6, 0xb1, 0xb2, 0x46, 0xc5, 0xc2, 0xdd, 0x53, 0x48, 0x9c, 0x1f, 0x39, 0x39, 0x78, 0x43, 0x41, 0x0c, 0x1a}; + unsigned char send_nf_ptr_1[] = {0x35, 0xf7, 0xff, 0x84, 0x5e, 0x47, 0x86, 0xd6, 0x44, 0xc9, 0xc9, 0x05, 0xfe, 0x68, 0xfd, 0x0f, 0x60, 0x2f, 0xea, 0x0b, 0xeb, 0x2c, 0x34, 0x1b, 0xc5, 0xd2, 0xde, 0xfc, 0x17, 0xc3, 0x2e, 0x86}; + unsigned char send_nf_ptr_2[] = {0x35, 0xf7, 0xff, 0x84, 0x5e, 0x47, 0x86, 0xd6, 0x44, 0xc9, 0xc9, 0x05, 0xfe, 0x68, 0xfd, 0x0f, 0x60, 0x2f, 0xea, 0x0b, 0xeb, 0x2c, 0x34, 0x1b, 0xc5, 0xd2, 0xde, 0xfc, 0x17, 0xc3, 0x2e, 0x86}; + unsigned char cm_ptr_1[] = {0xd6, 0x21, 0x8a, 0x07, 0x71, 0x4d, 0xd9, 0xfa, 0xc9, 0x2b, 0xde, 0xef, 0xd3, 0xf4, 0xc0, 0xd7, 0x69, 0xf4, 0x0f, 0x4b, 0x04, 0x3a, 0xd7, 0xe6, 0x7e, 0x73, 0x75, 0xed, 0xc4, 0x98, 0xe4, 0x5c}; + unsigned char cm_ptr_2[] = {0xd6, 0x21, 0x8a, 0x07, 0x71, 0x4d, 0xd9, 0xfa, 0xc9, 0x2b, 0xde, 0xef, 0xd3, 0xf4, 0xc0, 0xd7, 0x69, 0xf4, 0x0f, 0x4b, 0x04, 0x3a, 0xd7, 0xe6, 0x7e, 0x73, 0x75, 0xed, 0xc4, 0x98, 0xe4, 0x5c}; + + bool ret = zsl_verify_transfer(output_proof_ptr, anchor_ptr, spend_nf_ptr_1, spend_nf_ptr_2, send_nf_ptr_1, send_nf_ptr_2, cm_ptr_1, cm_ptr_2); + if(!ret) { + std::cout << "Verify transfer done" << std::endl; + } + + return true; +} + +int main(int argc, char *argv[]) +{ + zsl_initialize(); + + // shielding zk-snark test + //zsl_paramgen_shielding(); + bool ret = shielding(); + + // unsheilding zk-snark test + //zsl_paramgen_unshielding(); + ret = unshileding(); + + // transfer zk-snark test + //zsl_paramgen_transfer(); + //ret = shield_transfer(); + + /*if (argc != 2) return 1; + char* inp1 = argv[1]; + */ + + // get keypair test + /*std::string pub; + std::string priv; + get_keypair(pub, priv); + std::cout << "a_pk:" << pub << std::endl; + std::cout << "a_sk:" << priv << std::endl; + */ + + return 0; +} diff --git a/privacy/zsl/note.cpp b/privacy/zsl/note.cpp new file mode 100644 index 0000000..5ba6d1b --- /dev/null +++ b/privacy/zsl/note.cpp @@ -0,0 +1,28 @@ +#include "note.hpp" + +Note::Note() { + + std::string a_pk_str; + get_randomness(a_pk_str); + if(!a_pk_str.empty()) rho = uint256S(a_pk_str); + + std::string rho_str; + get_randomness(rho_str); + if(!rho_str.empty()) rho = uint256S(rho_str); +} + +uint256 Note::cm() { + std::string data; + data += a_pk.ToString(); + data += to_string(value); + data += rho.ToString(); + std::string output; + sha256(data, output); + return uint256S(output); +} + +uint256 Note::nullifier(const uint256& a_sk) const { + std::string output; + sha256(rho.ToString(), output); + return uint256S(output); +} diff --git a/privacy/zsl/note.hpp b/privacy/zsl/note.hpp new file mode 100644 index 0000000..a667a88 --- /dev/null +++ b/privacy/zsl/note.hpp @@ -0,0 +1,286 @@ +#ifndef _NOTE_HPP_ +#define _NOTE_HPP_ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "utils/util.h" + +template +std::string to_string(T value) { + std::ostringstream os; + os << value; + return os.str(); +} + +// hash function +void sha256(const std::string input, std::string& output) { + unsigned char hash[SHA256_DIGEST_LENGTH]; + SHA256_CTX sha256; + SHA256_Init(&sha256); + SHA256_Update(&sha256, input.c_str(), input.size()); + SHA256_Final((unsigned char*)output.c_str(), &sha256); +} + +void sha256(unsigned char *str, int len, unsigned char *buf) { + SHA256_CTX sha256; + SHA256_Init(&sha256); + SHA256_Update(&sha256, str, len); + SHA256_Final(buf, &sha256); +} + +/* +void hex_str_to_array(std::string& str, unsigned char * array) { + unsigned char array[str.size()/2]; + for(int i = 0; i < str.size(); i+=2) { + std::string sub = str.substr(i, 2); + array[i/2] = strtoul(sub.c_str(), 0, 16); + } +} +*/ +void hex_str_to_array(const std::string& hex_str, unsigned char *array) { + unsigned int c; + for (int i = 0; i < hex_str.size(); i+=2) { + std::istringstream hex_stream(hex_str.substr(i, 2)); + hex_stream >> std::hex >> c; + array[i/2] = c; + } +} + +void print_char_array(unsigned char *array, int len) { + for(int i=0; i < len; i++) + printf("%02x", array[i]); + printf("\n"); +} + +/* hex string to hex array */ +/*void hex_str_to_array(const std::string& hex_str, unsigned char * array) { + for(int i = 0; i < hex_str.size(); i+=2) { + char ch_h = hex_str[i]; + char ch_l = hex_str[i+1]; + unsigned int high = (ch_h >= 'A')? (ch_h - 'A' + 10): (ch_h - '0'); + unsigned int low = (ch_l >= 'A')? (ch_l - 'A' + 10): (ch_l - '0'); + array[i/2] = high * 16 + low; + } +}*/ + +/* binary data to hex string */ +static std::string BinToHexString(const std::string &value) { + std::string result; + result.resize(value.size() * 2); + for (size_t i = 0; i < value.size(); i++) { + uint8_t item = value[i]; + uint8_t high = (item >> 4); + uint8_t low = (item & 0x0F); + result[2 * i] = (high >= 0 && high <= 9) ? (high + '0') : (high - 10 + 'a'); + result[2 * i + 1] = (low >= 0 && low <= 9) ? (low + '0') : (low - 10 + 'a'); + } + return result; +} + +static std::string BinToHexString(const char *value, int len) { + std::string result; + result.resize(len * 2); + for (size_t i = 0; i < len; i++) { + uint8_t item = value[i]; + uint8_t high = (item >> 4); + uint8_t low = (item & 0x0F); + result[2 * i] = (high >= 0 && high <= 9) ? (high + '0') : (high - 10 + 'a'); + result[2 * i + 1] = (low >= 0 && low <= 9) ? (low + '0') : (low - 10 + 'a'); + } + return result; +} + +static void BinToHexArray(const char *value, int len, unsigned char *output) { + for (size_t i = 0; i < len; i++) { + uint8_t item = value[i]; + uint8_t high = (item >> 4); + uint8_t low = (item & 0x0F); + int valuex = (high << 4) + low; + output[i] = (char)valuex; + } + return; +} + +std::string HexStringToBin(const std::string &hex_string, bool force_little = false){ + if (hex_string.size() % 2 != 0 || hex_string.empty() ){ + return ""; + } + std::string result; + result.resize(hex_string.size()/2); + for (size_t i = 0; i < hex_string.size() - 1; i = i + 2){ + uint8_t high = 0; + if (hex_string[i] >= '0' && hex_string[i] <= '9') + high = (hex_string[i] - '0'); + else if (hex_string[i] >= 'a' && hex_string[i] <= 'f') + high = (hex_string[i] - 'a' + 10); + else if (hex_string[i] >= 'A' && hex_string[i] <= 'F' && !force_little) { + high = (hex_string[i] - 'A' + 10); + } + else { + return ""; + } + + uint8_t low = 0; + if (hex_string[i + 1] >= '0' && hex_string[i + 1] <= '9') + low = (hex_string[i + 1] - '0'); + else if (hex_string[i + 1] >= 'a' && hex_string[i + 1] <= 'f') + low = (hex_string[i + 1] - 'a' + 10); + else if (hex_string[i + 1] >= 'A' && hex_string[i + 1] <= 'F' && !force_little) { + low = (hex_string[i + 1] - 'A' + 10); + } + else { + return ""; + } + + int valuex = (high << 4) + low; + //sscanf(hex_string.substr(i, 2).c_str(), "%x", &valuex); + result.at(i/2) = (char)valuex; + } + + return result; +} + +static bool IsHexString(const std::string &hex_string) { + if (hex_string.size() % 2 != 0) { + return false; + } + for (size_t i = 0; i < hex_string.size(); i++) { + char c = hex_string.at(i); + if (('0' <= c &&c <= '9') || ('a' <= c&& c <= 'f') || ('A' <= c&& c <= 'F')) { + continue; + } + else + return false; + } + return true; +} +bool HexStringToBin(const std::string &hex_string, std::string &out_put) { + if (!IsHexString(hex_string)) { + return false; + } + out_put = HexStringToBin(hex_string); + return true; +} + +void HexStringToBin(const std::string &hex_string, unsigned char* output){ + if (hex_string.size() % 2 != 0 || hex_string.empty() ){ + return; + } + std::string result; + result.resize(hex_string.size()/2); + for (size_t i = 0; i < hex_string.size() - 1; i = i + 2){ + uint8_t high = 0; + if (hex_string[i] >= '0' && hex_string[i] <= '9') + high = (hex_string[i] - '0'); + else if (hex_string[i] >= 'a' && hex_string[i] <= 'f') + high = (hex_string[i] - 'a' + 10); + else if (hex_string[i] >= 'A' && hex_string[i] <= 'F') { + high = (hex_string[i] - 'A' + 10); + } + else { + return; + } + + uint8_t low = 0; + if (hex_string[i + 1] >= '0' && hex_string[i + 1] <= '9') + low = (hex_string[i + 1] - '0'); + else if (hex_string[i + 1] >= 'a' && hex_string[i + 1] <= 'f') + low = (hex_string[i + 1] - 'a' + 10); + else if (hex_string[i + 1] >= 'A' && hex_string[i + 1] <= 'F') { + low = (hex_string[i + 1] - 'A' + 10); + } + else { + return; + } + + int valuex = (high << 4) + low; + //sscanf(hex_string.substr(i, 2).c_str(), "%x", &valuex); + output[i/2] = (char)valuex; + } + + return; +} + +/* get random number */ +template +T get_randomness() +{ + union { + T value; + char cs[sizeof(T)]; + } u; + + std::ifstream rfin("/dev/urandom"); + rfin.read(u.cs, sizeof(u.cs)); + rfin.close(); + + return u.value; +} + +/* get random string hash(random_number) +void get_randomness(std::string& r) { + unsigned long long int random_value = 0; + size_t size = sizeof(random_value); + std::ifstream urandom("/dev/urandom", std::ios::in|std::ios::binary); + if(urandom) { + urandom.read(reinterpret_cast(&random_value), size); + //urandom.read(random_value, sizeof(random_value)); + if(urandom) { + sha256(to_string(random_value), r); + } + urandom.close(); + } + return; +}*/ + +void get_randomness(std::string &output, int len) { + char *buf = new char[len]; + std::ifstream urandom("/dev/urandom", std::ios::in|std::ios::binary); + if(urandom) { + urandom.read(buf, len); + if(urandom) { + output = BinToHexString(buf, len); + } + urandom.close(); + } + return; +} +void get_randomness(unsigned char *output, int len) { + std::string hex_str; + get_randomness(hex_str, len); + hex_str_to_array(hex_str, output); + return; +} + +/* get new address */ +void get_keypair(unsigned char *priv, unsigned char *pub) { + get_randomness(priv, 32); + sha256(priv, 32, pub); +} + +/* Note class */ +class Note { +public: + uint256 a_pk; + uint256 rho; + + uint64_t value = 0; + + Note(uint256 a_pk, uint64_t value, uint256 rho) + : value(value), a_pk(a_pk), rho(rho) {} + Note(); + ~Note() {}; + + uint256 cm() const; // hash(rho, a_pk, value) + uint256 nullifier(const uint256& a_sk) const; // hash(rho, a_sk) +}; + +#endif diff --git a/privacy/zsl/utils/sha256.cpp b/privacy/zsl/utils/sha256.cpp new file mode 100644 index 0000000..c64d1ad --- /dev/null +++ b/privacy/zsl/utils/sha256.cpp @@ -0,0 +1,130 @@ +/********************************************************************* +* Filename: sha256.c +* Author: Brad Conte (brad AT bradconte.com) +* Copyright: +* Disclaimer: This code is presented "as is" without any guarantees. +* Details: Implementation of the SHA-256 hashing algorithm. + SHA-256 is one of the three algorithms in the SHA2 + specification. The others, SHA-384 and SHA-512, are not + offered in this implementation. + Algorithm specification can be found here: + * http://csrc.nist.gov/publications/fips/fips180-2/fips180-2withchangenotice.pdf + This implementation uses little endian byte order. +*********************************************************************/ + +/*************************** HEADER FILES ***************************/ +#include +#include +#include "sha256.h" + +/****************************** MACROS ******************************/ +#define ROTLEFT(a,b) (((a) << (b)) | ((a) >> (32-(b)))) +#define ROTRIGHT(a,b) (((a) >> (b)) | ((a) << (32-(b)))) + +#define CH(x,y,z) (((x) & (y)) ^ (~(x) & (z))) +#define MAJ(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z))) +#define EP0(x) (ROTRIGHT(x,2) ^ ROTRIGHT(x,13) ^ ROTRIGHT(x,22)) +#define EP1(x) (ROTRIGHT(x,6) ^ ROTRIGHT(x,11) ^ ROTRIGHT(x,25)) +#define SIG0(x) (ROTRIGHT(x,7) ^ ROTRIGHT(x,18) ^ ((x) >> 3)) +#define SIG1(x) (ROTRIGHT(x,17) ^ ROTRIGHT(x,19) ^ ((x) >> 10)) + +/**************************** VARIABLES *****************************/ +static const WORD k[64] = { + 0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5,0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5, + 0xd807aa98,0x12835b01,0x243185be,0x550c7dc3,0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174, + 0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc,0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da, + 0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7,0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967, + 0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13,0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85, + 0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3,0xd192e819,0xd6990624,0xf40e3585,0x106aa070, + 0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5,0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3, + 0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208,0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2 +}; + +/*********************** FUNCTION DEFINITIONS ***********************/ +void sha256_transform(SHA256_CTX_mod *ctx, const BYTE data[]) +{ + WORD a, b, c, d, e, f, g, h, i, j, t1, t2, m[64]; + + for (i = 0, j = 0; i < 16; ++i, j += 4) + m[i] = (data[j] << 24) | (data[j + 1] << 16) | (data[j + 2] << 8) | (data[j + 3]); + for ( ; i < 64; ++i) + m[i] = SIG1(m[i - 2]) + m[i - 7] + SIG0(m[i - 15]) + m[i - 16]; + + a = ctx->state[0]; + b = ctx->state[1]; + c = ctx->state[2]; + d = ctx->state[3]; + e = ctx->state[4]; + f = ctx->state[5]; + g = ctx->state[6]; + h = ctx->state[7]; + + for (i = 0; i < 64; ++i) { + t1 = h + EP1(e) + CH(e,f,g) + k[i] + m[i]; + t2 = EP0(a) + MAJ(a,b,c); + h = g; + g = f; + f = e; + e = d + t1; + d = c; + c = b; + b = a; + a = t1 + t2; + } + + ctx->state[0] += a; + ctx->state[1] += b; + ctx->state[2] += c; + ctx->state[3] += d; + ctx->state[4] += e; + ctx->state[5] += f; + ctx->state[6] += g; + ctx->state[7] += h; +} + +void sha256_init(SHA256_CTX_mod *ctx) +{ + ctx->datalen = 0; + ctx->bitlen = 0; + ctx->state[0] = 0x6a09e667; + ctx->state[1] = 0xbb67ae85; + ctx->state[2] = 0x3c6ef372; + ctx->state[3] = 0xa54ff53a; + ctx->state[4] = 0x510e527f; + ctx->state[5] = 0x9b05688c; + ctx->state[6] = 0x1f83d9ab; + ctx->state[7] = 0x5be0cd19; +} + +void sha256_update(SHA256_CTX_mod *ctx, const BYTE data[], size_t len) +{ + WORD i; + + for (i = 0; i < len; ++i) { + ctx->data[ctx->datalen] = data[i]; + ctx->datalen++; + if (ctx->datalen == 64) { + sha256_transform(ctx, ctx->data); + ctx->bitlen += 512; + ctx->datalen = 0; + } + } +} + +void sha256_final(SHA256_CTX_mod *ctx, BYTE hash[]) +{ + WORD i; + + i = ctx->datalen; + + for (i = 0; i < 4; ++i) { + hash[i] = (ctx->state[0] >> (24 - i * 8)) & 0x000000ff; + hash[i + 4] = (ctx->state[1] >> (24 - i * 8)) & 0x000000ff; + hash[i + 8] = (ctx->state[2] >> (24 - i * 8)) & 0x000000ff; + hash[i + 12] = (ctx->state[3] >> (24 - i * 8)) & 0x000000ff; + hash[i + 16] = (ctx->state[4] >> (24 - i * 8)) & 0x000000ff; + hash[i + 20] = (ctx->state[5] >> (24 - i * 8)) & 0x000000ff; + hash[i + 24] = (ctx->state[6] >> (24 - i * 8)) & 0x000000ff; + hash[i + 28] = (ctx->state[7] >> (24 - i * 8)) & 0x000000ff; + } +} diff --git a/privacy/zsl/utils/sha256.h b/privacy/zsl/utils/sha256.h new file mode 100644 index 0000000..9f6afa1 --- /dev/null +++ b/privacy/zsl/utils/sha256.h @@ -0,0 +1,34 @@ +/********************************************************************* +* Filename: sha256.h +* Author: Brad Conte (brad AT bradconte.com) +* Copyright: +* Disclaimer: This code is presented "as is" without any guarantees. +* Details: Defines the API for the corresponding SHA1 implementation. +*********************************************************************/ + +#ifndef SHA256H_H +#define SHA256H_H + +/*************************** HEADER FILES ***************************/ +#include + +/****************************** MACROS ******************************/ +#define SHA256_BLOCK_SIZE 32 // SHA256 outputs a 32 byte digest + +/**************************** DATA TYPES ****************************/ +typedef unsigned char BYTE; // 8-bit byte +typedef unsigned int WORD; // 32-bit word, change to "long" for 16-bit machines + +typedef struct { + BYTE data[64]; + WORD datalen; + unsigned long long bitlen; + WORD state[8]; +} SHA256_CTX_mod; + +/*********************** FUNCTION DECLARATIONS **********************/ +void sha256_init(SHA256_CTX_mod *ctx); +void sha256_update(SHA256_CTX_mod *ctx, const BYTE data[], size_t len); +void sha256_final(SHA256_CTX_mod *ctx, BYTE hash[]); + +#endif // SHA256H_H diff --git a/privacy/zsl/utils/tinyformat.h b/privacy/zsl/utils/tinyformat.h new file mode 100644 index 0000000..57f7672 --- /dev/null +++ b/privacy/zsl/utils/tinyformat.h @@ -0,0 +1,1049 @@ +// tinyformat.h +// Copyright (C) 2011, Chris Foster [chris42f (at) gmail (d0t) com] +// +// Boost Software License - Version 1.0 +// +// Permission is hereby granted, free of charge, to any person or organization +// obtaining a copy of the software and accompanying documentation covered by +// this license (the "Software") to use, reproduce, display, distribute, +// execute, and transmit the Software, and to prepare derivative works of the +// Software, and to permit third-parties to whom the Software is furnished to +// do so, all subject to the following: +// +// The copyright notices in the Software and this entire statement, including +// the above license grant, this restriction and the following disclaimer, +// must be included in all copies of the Software, in whole or in part, and +// all derivative works of the Software, unless such copies or derivative +// works are solely in the form of machine-executable object code generated by +// a source language processor. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +//------------------------------------------------------------------------------ +// Tinyformat: A minimal type safe printf replacement +// +// tinyformat.h is a type safe printf replacement library in a single C++ +// header file. Design goals include: +// +// * Type safety and extensibility for user defined types. +// * C99 printf() compatibility, to the extent possible using std::ostream +// * Simplicity and minimalism. A single header file to include and distribute +// with your projects. +// * Augment rather than replace the standard stream formatting mechanism +// * C++98 support, with optional C++11 niceties +// +// +// Main interface example usage +// ---------------------------- +// +// To print a date to std::cout: +// +// std::string weekday = "Wednesday"; +// const char* month = "July"; +// size_t day = 27; +// long hour = 14; +// int min = 44; +// +// tfm::printf("%s, %s %d, %.2d:%.2d\n", weekday, month, day, hour, min); +// +// The strange types here emphasize the type safety of the interface; it is +// possible to print a std::string using the "%s" conversion, and a +// size_t using the "%d" conversion. A similar result could be achieved +// using either of the tfm::format() functions. One prints on a user provided +// stream: +// +// tfm::format(std::cerr, "%s, %s %d, %.2d:%.2d\n", +// weekday, month, day, hour, min); +// +// The other returns a std::string: +// +// std::string date = tfm::format("%s, %s %d, %.2d:%.2d\n", +// weekday, month, day, hour, min); +// std::cout << date; +// +// These are the three primary interface functions. There is also a +// convenience function printfln() which appends a newline to the usual result +// of printf() for super simple logging. +// +// +// User defined format functions +// ----------------------------- +// +// Simulating variadic templates in C++98 is pretty painful since it requires +// writing out the same function for each desired number of arguments. To make +// this bearable tinyformat comes with a set of macros which are used +// internally to generate the API, but which may also be used in user code. +// +// The three macros TINYFORMAT_ARGTYPES(n), TINYFORMAT_VARARGS(n) and +// TINYFORMAT_PASSARGS(n) will generate a list of n argument types, +// type/name pairs and argument names respectively when called with an integer +// n between 1 and 16. We can use these to define a macro which generates the +// desired user defined function with n arguments. To generate all 16 user +// defined function bodies, use the macro TINYFORMAT_FOREACH_ARGNUM. For an +// example, see the implementation of printf() at the end of the source file. +// +// Sometimes it's useful to be able to pass a list of format arguments through +// to a non-template function. The FormatList class is provided as a way to do +// this by storing the argument list in a type-opaque way. Continuing the +// example from above, we construct a FormatList using makeFormatList(): +// +// FormatListRef formatList = tfm::makeFormatList(weekday, month, day, hour, min); +// +// The format list can now be passed into any non-template function and used +// via a call to the vformat() function: +// +// tfm::vformat(std::cout, "%s, %s %d, %.2d:%.2d\n", formatList); +// +// +// Additional API information +// -------------------------- +// +// Error handling: Define TINYFORMAT_ERROR to customize the error handling for +// format strings which are unsupported or have the wrong number of format +// specifiers (calls assert() by default). +// +// User defined types: Uses operator<< for user defined types by default. +// Overload formatValue() for more control. + + +#ifndef TINYFORMAT_H_INCLUDED +#define TINYFORMAT_H_INCLUDED + +namespace tinyformat {} +//------------------------------------------------------------------------------ +// Config section. Customize to your liking! + +// Namespace alias to encourage brevity +namespace tfm = tinyformat; + +// Error handling; calls assert() by default. +#define TINYFORMAT_ERROR(reasonString) throw std::runtime_error(reasonString) + +// Define for C++11 variadic templates which make the code shorter & more +// general. If you don't define this, C++11 support is autodetected below. +// #define TINYFORMAT_USE_VARIADIC_TEMPLATES + + +//------------------------------------------------------------------------------ +// Implementation details. +#include +#include +#include +#include +#include + +#ifndef TINYFORMAT_ERROR +# define TINYFORMAT_ERROR(reason) assert(0 && reason) +#endif + +#if !defined(TINYFORMAT_USE_VARIADIC_TEMPLATES) && !defined(TINYFORMAT_NO_VARIADIC_TEMPLATES) +# ifdef __GXX_EXPERIMENTAL_CXX0X__ +# define TINYFORMAT_USE_VARIADIC_TEMPLATES +# endif +#endif + +#if defined(__GLIBCXX__) && __GLIBCXX__ < 20080201 +// std::showpos is broken on old libstdc++ as provided with OSX. See +// http://gcc.gnu.org/ml/libstdc++/2007-11/msg00075.html +# define TINYFORMAT_OLD_LIBSTDCPLUSPLUS_WORKAROUND +#endif + +#ifdef __APPLE__ +// Workaround macOS linker warning: Xcode uses different default symbol +// visibilities for static libs vs executables (see issue #25) +# define TINYFORMAT_HIDDEN __attribute__((visibility("hidden"))) +#else +# define TINYFORMAT_HIDDEN +#endif + +namespace tinyformat { + +//------------------------------------------------------------------------------ +namespace detail { + +// Test whether type T1 is convertible to type T2 +template +struct is_convertible +{ + private: + // two types of different size + struct fail { char dummy[2]; }; + struct succeed { char dummy; }; + // Try to convert a T1 to a T2 by plugging into tryConvert + static fail tryConvert(...); + static succeed tryConvert(const T2&); + static const T1& makeT1(); + public: +# ifdef _MSC_VER + // Disable spurious loss of precision warnings in tryConvert(makeT1()) +# pragma warning(push) +# pragma warning(disable:4244) +# pragma warning(disable:4267) +# endif + // Standard trick: the (...) version of tryConvert will be chosen from + // the overload set only if the version taking a T2 doesn't match. + // Then we compare the sizes of the return types to check which + // function matched. Very neat, in a disgusting kind of way :) + static const bool value = + sizeof(tryConvert(makeT1())) == sizeof(succeed); +# ifdef _MSC_VER +# pragma warning(pop) +# endif +}; + + +// Detect when a type is not a wchar_t string +template struct is_wchar { typedef int tinyformat_wchar_is_not_supported; }; +template<> struct is_wchar {}; +template<> struct is_wchar {}; +template struct is_wchar {}; +template struct is_wchar {}; + + +// Format the value by casting to type fmtT. This default implementation +// should never be called. +template::value> +struct formatValueAsType +{ + static void invoke(std::ostream& /*out*/, const T& /*value*/) { assert(0); } +}; +// Specialized version for types that can actually be converted to fmtT, as +// indicated by the "convertible" template parameter. +template +struct formatValueAsType +{ + static void invoke(std::ostream& out, const T& value) + { out << static_cast(value); } +}; + +#ifdef TINYFORMAT_OLD_LIBSTDCPLUSPLUS_WORKAROUND +template::value> +struct formatZeroIntegerWorkaround +{ + static bool invoke(std::ostream& /**/, const T& /**/) { return false; } +}; +template +struct formatZeroIntegerWorkaround +{ + static bool invoke(std::ostream& out, const T& value) + { + if (static_cast(value) == 0 && out.flags() & std::ios::showpos) + { + out << "+0"; + return true; + } + return false; + } +}; +#endif // TINYFORMAT_OLD_LIBSTDCPLUSPLUS_WORKAROUND + +// Convert an arbitrary type to integer. The version with convertible=false +// throws an error. +template::value> +struct convertToInt +{ + static int invoke(const T& /*value*/) + { + TINYFORMAT_ERROR("tinyformat: Cannot convert from argument type to " + "integer for use as variable width or precision"); + return 0; + } +}; +// Specialization for convertToInt when conversion is possible +template +struct convertToInt +{ + static int invoke(const T& value) { return static_cast(value); } +}; + +// Format at most ntrunc characters to the given stream. +template +inline void formatTruncated(std::ostream& out, const T& value, int ntrunc) +{ + std::ostringstream tmp; + tmp << value; + std::string result = tmp.str(); + out.write(result.c_str(), (std::min)(ntrunc, static_cast(result.size()))); +} +#define TINYFORMAT_DEFINE_FORMAT_TRUNCATED_CSTR(type) \ +inline void formatTruncated(std::ostream& out, type* value, int ntrunc) \ +{ \ + std::streamsize len = 0; \ + while(len < ntrunc && value[len] != 0) \ + ++len; \ + out.write(value, len); \ +} +// Overload for const char* and char*. Could overload for signed & unsigned +// char too, but these are technically unneeded for printf compatibility. +TINYFORMAT_DEFINE_FORMAT_TRUNCATED_CSTR(const char) +TINYFORMAT_DEFINE_FORMAT_TRUNCATED_CSTR(char) +#undef TINYFORMAT_DEFINE_FORMAT_TRUNCATED_CSTR + +} // namespace detail + + +//------------------------------------------------------------------------------ +// Variable formatting functions. May be overridden for user-defined types if +// desired. + + +/// Format a value into a stream, delegating to operator<< by default. +/// +/// Users may override this for their own types. When this function is called, +/// the stream flags will have been modified according to the format string. +/// The format specification is provided in the range [fmtBegin, fmtEnd). For +/// truncating conversions, ntrunc is set to the desired maximum number of +/// characters, for example "%.7s" calls formatValue with ntrunc = 7. +/// +/// By default, formatValue() uses the usual stream insertion operator +/// operator<< to format the type T, with special cases for the %c and %p +/// conversions. +template +inline void formatValue(std::ostream& out, const char* /*fmtBegin*/, + const char* fmtEnd, int ntrunc, const T& value) +{ +#ifndef TINYFORMAT_ALLOW_WCHAR_STRINGS + // Since we don't support printing of wchar_t using "%ls", make it fail at + // compile time in preference to printing as a void* at runtime. + typedef typename detail::is_wchar::tinyformat_wchar_is_not_supported DummyType; + (void) DummyType(); // avoid unused type warning with gcc-4.8 +#endif + // The mess here is to support the %c and %p conversions: if these + // conversions are active we try to convert the type to a char or const + // void* respectively and format that instead of the value itself. For the + // %p conversion it's important to avoid dereferencing the pointer, which + // could otherwise lead to a crash when printing a dangling (const char*). + const bool canConvertToChar = detail::is_convertible::value; + const bool canConvertToVoidPtr = detail::is_convertible::value; + if(canConvertToChar && *(fmtEnd-1) == 'c') + detail::formatValueAsType::invoke(out, value); + else if(canConvertToVoidPtr && *(fmtEnd-1) == 'p') + detail::formatValueAsType::invoke(out, value); +#ifdef TINYFORMAT_OLD_LIBSTDCPLUSPLUS_WORKAROUND + else if(detail::formatZeroIntegerWorkaround::invoke(out, value)) /**/; +#endif + else if(ntrunc >= 0) + { + // Take care not to overread C strings in truncating conversions like + // "%.4s" where at most 4 characters may be read. + detail::formatTruncated(out, value, ntrunc); + } + else + out << value; +} + + +// Overloaded version for char types to support printing as an integer +#define TINYFORMAT_DEFINE_FORMATVALUE_CHAR(charType) \ +inline void formatValue(std::ostream& out, const char* /*fmtBegin*/, \ + const char* fmtEnd, int /**/, charType value) \ +{ \ + switch(*(fmtEnd-1)) \ + { \ + case 'u': case 'd': case 'i': case 'o': case 'X': case 'x': \ + out << static_cast(value); break; \ + default: \ + out << value; break; \ + } \ +} +// per 3.9.1: char, signed char and unsigned char are all distinct types +TINYFORMAT_DEFINE_FORMATVALUE_CHAR(char) +TINYFORMAT_DEFINE_FORMATVALUE_CHAR(signed char) +TINYFORMAT_DEFINE_FORMATVALUE_CHAR(unsigned char) +#undef TINYFORMAT_DEFINE_FORMATVALUE_CHAR + + +//------------------------------------------------------------------------------ +// Tools for emulating variadic templates in C++98. The basic idea here is +// stolen from the boost preprocessor metaprogramming library and cut down to +// be just general enough for what we need. + +#define TINYFORMAT_ARGTYPES(n) TINYFORMAT_ARGTYPES_ ## n +#define TINYFORMAT_VARARGS(n) TINYFORMAT_VARARGS_ ## n +#define TINYFORMAT_PASSARGS(n) TINYFORMAT_PASSARGS_ ## n +#define TINYFORMAT_PASSARGS_TAIL(n) TINYFORMAT_PASSARGS_TAIL_ ## n + +// To keep it as transparent as possible, the macros below have been generated +// using python via the excellent cog.py code generation script. This avoids +// the need for a bunch of complex (but more general) preprocessor tricks as +// used in boost.preprocessor. +// +// To rerun the code generation in place, use `cog.py -r tinyformat.h` +// (see http://nedbatchelder.com/code/cog). Alternatively you can just create +// extra versions by hand. + +/*[[[cog +maxParams = 16 + +def makeCommaSepLists(lineTemplate, elemTemplate, startInd=1): + for j in range(startInd,maxParams+1): + list = ', '.join([elemTemplate % {'i':i} for i in range(startInd,j+1)]) + cog.outl(lineTemplate % {'j':j, 'list':list}) + +makeCommaSepLists('#define TINYFORMAT_ARGTYPES_%(j)d %(list)s', + 'class T%(i)d') + +cog.outl() +makeCommaSepLists('#define TINYFORMAT_VARARGS_%(j)d %(list)s', + 'const T%(i)d& v%(i)d') + +cog.outl() +makeCommaSepLists('#define TINYFORMAT_PASSARGS_%(j)d %(list)s', 'v%(i)d') + +cog.outl() +cog.outl('#define TINYFORMAT_PASSARGS_TAIL_1') +makeCommaSepLists('#define TINYFORMAT_PASSARGS_TAIL_%(j)d , %(list)s', + 'v%(i)d', startInd = 2) + +cog.outl() +cog.outl('#define TINYFORMAT_FOREACH_ARGNUM(m) \\\n ' + + ' '.join(['m(%d)' % (j,) for j in range(1,maxParams+1)])) +]]]*/ +#define TINYFORMAT_ARGTYPES_1 class T1 +#define TINYFORMAT_ARGTYPES_2 class T1, class T2 +#define TINYFORMAT_ARGTYPES_3 class T1, class T2, class T3 +#define TINYFORMAT_ARGTYPES_4 class T1, class T2, class T3, class T4 +#define TINYFORMAT_ARGTYPES_5 class T1, class T2, class T3, class T4, class T5 +#define TINYFORMAT_ARGTYPES_6 class T1, class T2, class T3, class T4, class T5, class T6 +#define TINYFORMAT_ARGTYPES_7 class T1, class T2, class T3, class T4, class T5, class T6, class T7 +#define TINYFORMAT_ARGTYPES_8 class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8 +#define TINYFORMAT_ARGTYPES_9 class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9 +#define TINYFORMAT_ARGTYPES_10 class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9, class T10 +#define TINYFORMAT_ARGTYPES_11 class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9, class T10, class T11 +#define TINYFORMAT_ARGTYPES_12 class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9, class T10, class T11, class T12 +#define TINYFORMAT_ARGTYPES_13 class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9, class T10, class T11, class T12, class T13 +#define TINYFORMAT_ARGTYPES_14 class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9, class T10, class T11, class T12, class T13, class T14 +#define TINYFORMAT_ARGTYPES_15 class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9, class T10, class T11, class T12, class T13, class T14, class T15 +#define TINYFORMAT_ARGTYPES_16 class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9, class T10, class T11, class T12, class T13, class T14, class T15, class T16 + +#define TINYFORMAT_VARARGS_1 const T1& v1 +#define TINYFORMAT_VARARGS_2 const T1& v1, const T2& v2 +#define TINYFORMAT_VARARGS_3 const T1& v1, const T2& v2, const T3& v3 +#define TINYFORMAT_VARARGS_4 const T1& v1, const T2& v2, const T3& v3, const T4& v4 +#define TINYFORMAT_VARARGS_5 const T1& v1, const T2& v2, const T3& v3, const T4& v4, const T5& v5 +#define TINYFORMAT_VARARGS_6 const T1& v1, const T2& v2, const T3& v3, const T4& v4, const T5& v5, const T6& v6 +#define TINYFORMAT_VARARGS_7 const T1& v1, const T2& v2, const T3& v3, const T4& v4, const T5& v5, const T6& v6, const T7& v7 +#define TINYFORMAT_VARARGS_8 const T1& v1, const T2& v2, const T3& v3, const T4& v4, const T5& v5, const T6& v6, const T7& v7, const T8& v8 +#define TINYFORMAT_VARARGS_9 const T1& v1, const T2& v2, const T3& v3, const T4& v4, const T5& v5, const T6& v6, const T7& v7, const T8& v8, const T9& v9 +#define TINYFORMAT_VARARGS_10 const T1& v1, const T2& v2, const T3& v3, const T4& v4, const T5& v5, const T6& v6, const T7& v7, const T8& v8, const T9& v9, const T10& v10 +#define TINYFORMAT_VARARGS_11 const T1& v1, const T2& v2, const T3& v3, const T4& v4, const T5& v5, const T6& v6, const T7& v7, const T8& v8, const T9& v9, const T10& v10, const T11& v11 +#define TINYFORMAT_VARARGS_12 const T1& v1, const T2& v2, const T3& v3, const T4& v4, const T5& v5, const T6& v6, const T7& v7, const T8& v8, const T9& v9, const T10& v10, const T11& v11, const T12& v12 +#define TINYFORMAT_VARARGS_13 const T1& v1, const T2& v2, const T3& v3, const T4& v4, const T5& v5, const T6& v6, const T7& v7, const T8& v8, const T9& v9, const T10& v10, const T11& v11, const T12& v12, const T13& v13 +#define TINYFORMAT_VARARGS_14 const T1& v1, const T2& v2, const T3& v3, const T4& v4, const T5& v5, const T6& v6, const T7& v7, const T8& v8, const T9& v9, const T10& v10, const T11& v11, const T12& v12, const T13& v13, const T14& v14 +#define TINYFORMAT_VARARGS_15 const T1& v1, const T2& v2, const T3& v3, const T4& v4, const T5& v5, const T6& v6, const T7& v7, const T8& v8, const T9& v9, const T10& v10, const T11& v11, const T12& v12, const T13& v13, const T14& v14, const T15& v15 +#define TINYFORMAT_VARARGS_16 const T1& v1, const T2& v2, const T3& v3, const T4& v4, const T5& v5, const T6& v6, const T7& v7, const T8& v8, const T9& v9, const T10& v10, const T11& v11, const T12& v12, const T13& v13, const T14& v14, const T15& v15, const T16& v16 + +#define TINYFORMAT_PASSARGS_1 v1 +#define TINYFORMAT_PASSARGS_2 v1, v2 +#define TINYFORMAT_PASSARGS_3 v1, v2, v3 +#define TINYFORMAT_PASSARGS_4 v1, v2, v3, v4 +#define TINYFORMAT_PASSARGS_5 v1, v2, v3, v4, v5 +#define TINYFORMAT_PASSARGS_6 v1, v2, v3, v4, v5, v6 +#define TINYFORMAT_PASSARGS_7 v1, v2, v3, v4, v5, v6, v7 +#define TINYFORMAT_PASSARGS_8 v1, v2, v3, v4, v5, v6, v7, v8 +#define TINYFORMAT_PASSARGS_9 v1, v2, v3, v4, v5, v6, v7, v8, v9 +#define TINYFORMAT_PASSARGS_10 v1, v2, v3, v4, v5, v6, v7, v8, v9, v10 +#define TINYFORMAT_PASSARGS_11 v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11 +#define TINYFORMAT_PASSARGS_12 v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12 +#define TINYFORMAT_PASSARGS_13 v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13 +#define TINYFORMAT_PASSARGS_14 v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14 +#define TINYFORMAT_PASSARGS_15 v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15 +#define TINYFORMAT_PASSARGS_16 v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16 + +#define TINYFORMAT_PASSARGS_TAIL_1 +#define TINYFORMAT_PASSARGS_TAIL_2 , v2 +#define TINYFORMAT_PASSARGS_TAIL_3 , v2, v3 +#define TINYFORMAT_PASSARGS_TAIL_4 , v2, v3, v4 +#define TINYFORMAT_PASSARGS_TAIL_5 , v2, v3, v4, v5 +#define TINYFORMAT_PASSARGS_TAIL_6 , v2, v3, v4, v5, v6 +#define TINYFORMAT_PASSARGS_TAIL_7 , v2, v3, v4, v5, v6, v7 +#define TINYFORMAT_PASSARGS_TAIL_8 , v2, v3, v4, v5, v6, v7, v8 +#define TINYFORMAT_PASSARGS_TAIL_9 , v2, v3, v4, v5, v6, v7, v8, v9 +#define TINYFORMAT_PASSARGS_TAIL_10 , v2, v3, v4, v5, v6, v7, v8, v9, v10 +#define TINYFORMAT_PASSARGS_TAIL_11 , v2, v3, v4, v5, v6, v7, v8, v9, v10, v11 +#define TINYFORMAT_PASSARGS_TAIL_12 , v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12 +#define TINYFORMAT_PASSARGS_TAIL_13 , v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13 +#define TINYFORMAT_PASSARGS_TAIL_14 , v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14 +#define TINYFORMAT_PASSARGS_TAIL_15 , v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15 +#define TINYFORMAT_PASSARGS_TAIL_16 , v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16 + +#define TINYFORMAT_FOREACH_ARGNUM(m) \ + m(1) m(2) m(3) m(4) m(5) m(6) m(7) m(8) m(9) m(10) m(11) m(12) m(13) m(14) m(15) m(16) +//[[[end]]] + + + +namespace detail { + +// Type-opaque holder for an argument to format(), with associated actions on +// the type held as explicit function pointers. This allows FormatArg's for +// each argument to be allocated as a homogenous array inside FormatList +// whereas a naive implementation based on inheritance does not. +class FormatArg +{ + public: + FormatArg() {} + + template + FormatArg(const T& value) + : m_value(static_cast(&value)), + m_formatImpl(&formatImpl), + m_toIntImpl(&toIntImpl) + { } + + void format(std::ostream& out, const char* fmtBegin, + const char* fmtEnd, int ntrunc) const + { + m_formatImpl(out, fmtBegin, fmtEnd, ntrunc, m_value); + } + + int toInt() const + { + return m_toIntImpl(m_value); + } + + private: + template + TINYFORMAT_HIDDEN static void formatImpl(std::ostream& out, const char* fmtBegin, + const char* fmtEnd, int ntrunc, const void* value) + { + formatValue(out, fmtBegin, fmtEnd, ntrunc, *static_cast(value)); + } + + template + TINYFORMAT_HIDDEN static int toIntImpl(const void* value) + { + return convertToInt::invoke(*static_cast(value)); + } + + const void* m_value; + void (*m_formatImpl)(std::ostream& out, const char* fmtBegin, + const char* fmtEnd, int ntrunc, const void* value); + int (*m_toIntImpl)(const void* value); +}; + + +// Parse and return an integer from the string c, as atoi() +// On return, c is set to one past the end of the integer. +inline int parseIntAndAdvance(const char*& c) +{ + int i = 0; + for(;*c >= '0' && *c <= '9'; ++c) + i = 10*i + (*c - '0'); + return i; +} + +// Print literal part of format string and return next format spec +// position. +// +// Skips over any occurrences of '%%', printing a literal '%' to the +// output. The position of the first % character of the next +// nontrivial format spec is returned, or the end of string. +inline const char* printFormatStringLiteral(std::ostream& out, const char* fmt) +{ + const char* c = fmt; + for(;; ++c) + { + switch(*c) + { + case '\0': + out.write(fmt, c - fmt); + return c; + case '%': + out.write(fmt, c - fmt); + if(*(c+1) != '%') + return c; + // for "%%", tack trailing % onto next literal section. + fmt = ++c; + break; + default: + break; + } + } +} + + +// Parse a format string and set the stream state accordingly. +// +// The format mini-language recognized here is meant to be the one from C99, +// with the form "%[flags][width][.precision][length]type". +// +// Formatting options which can't be natively represented using the ostream +// state are returned in spacePadPositive (for space padded positive numbers) +// and ntrunc (for truncating conversions). argIndex is incremented if +// necessary to pull out variable width and precision. The function returns a +// pointer to the character after the end of the current format spec. +inline const char* streamStateFromFormat(std::ostream& out, bool& spacePadPositive, + int& ntrunc, const char* fmtStart, + const detail::FormatArg* formatters, + int& argIndex, int numFormatters) +{ + if(*fmtStart != '%') + { + TINYFORMAT_ERROR("tinyformat: Not enough conversion specifiers in format string"); + return fmtStart; + } + // Reset stream state to defaults. + out.width(0); + out.precision(6); + out.fill(' '); + // Reset most flags; ignore irrelevant unitbuf & skipws. + out.unsetf(std::ios::adjustfield | std::ios::basefield | + std::ios::floatfield | std::ios::showbase | std::ios::boolalpha | + std::ios::showpoint | std::ios::showpos | std::ios::uppercase); + bool precisionSet = false; + bool widthSet = false; + int widthExtra = 0; + const char* c = fmtStart + 1; + // 1) Parse flags + for(;; ++c) + { + switch(*c) + { + case '#': + out.setf(std::ios::showpoint | std::ios::showbase); + continue; + case '0': + // overridden by left alignment ('-' flag) + if(!(out.flags() & std::ios::left)) + { + // Use internal padding so that numeric values are + // formatted correctly, eg -00010 rather than 000-10 + out.fill('0'); + out.setf(std::ios::internal, std::ios::adjustfield); + } + continue; + case '-': + out.fill(' '); + out.setf(std::ios::left, std::ios::adjustfield); + continue; + case ' ': + // overridden by show positive sign, '+' flag. + if(!(out.flags() & std::ios::showpos)) + spacePadPositive = true; + continue; + case '+': + out.setf(std::ios::showpos); + spacePadPositive = false; + widthExtra = 1; + continue; + default: + break; + } + break; + } + // 2) Parse width + if(*c >= '0' && *c <= '9') + { + widthSet = true; + out.width(parseIntAndAdvance(c)); + } + if(*c == '*') + { + widthSet = true; + int width = 0; + if(argIndex < numFormatters) + width = formatters[argIndex++].toInt(); + else + TINYFORMAT_ERROR("tinyformat: Not enough arguments to read variable width"); + if(width < 0) + { + // negative widths correspond to '-' flag set + out.fill(' '); + out.setf(std::ios::left, std::ios::adjustfield); + width = -width; + } + out.width(width); + ++c; + } + // 3) Parse precision + if(*c == '.') + { + ++c; + int precision = 0; + if(*c == '*') + { + ++c; + if(argIndex < numFormatters) + precision = formatters[argIndex++].toInt(); + else + TINYFORMAT_ERROR("tinyformat: Not enough arguments to read variable precision"); + } + else + { + if(*c >= '0' && *c <= '9') + precision = parseIntAndAdvance(c); + else if(*c == '-') // negative precisions ignored, treated as zero. + parseIntAndAdvance(++c); + } + out.precision(precision); + precisionSet = true; + } + // 4) Ignore any C99 length modifier + while(*c == 'l' || *c == 'h' || *c == 'L' || + *c == 'j' || *c == 'z' || *c == 't') + ++c; + // 5) We're up to the conversion specifier character. + // Set stream flags based on conversion specifier (thanks to the + // boost::format class for forging the way here). + bool intConversion = false; + switch(*c) + { + case 'u': case 'd': case 'i': + out.setf(std::ios::dec, std::ios::basefield); + intConversion = true; + break; + case 'o': + out.setf(std::ios::oct, std::ios::basefield); + intConversion = true; + break; + case 'X': + out.setf(std::ios::uppercase); + case 'x': case 'p': + out.setf(std::ios::hex, std::ios::basefield); + intConversion = true; + break; + case 'E': + out.setf(std::ios::uppercase); + case 'e': + out.setf(std::ios::scientific, std::ios::floatfield); + out.setf(std::ios::dec, std::ios::basefield); + break; + case 'F': + out.setf(std::ios::uppercase); + case 'f': + out.setf(std::ios::fixed, std::ios::floatfield); + break; + case 'G': + out.setf(std::ios::uppercase); + case 'g': + out.setf(std::ios::dec, std::ios::basefield); + // As in boost::format, let stream decide float format. + out.flags(out.flags() & ~std::ios::floatfield); + break; + case 'a': case 'A': + TINYFORMAT_ERROR("tinyformat: the %a and %A conversion specs " + "are not supported"); + break; + case 'c': + // Handled as special case inside formatValue() + break; + case 's': + if(precisionSet) + ntrunc = static_cast(out.precision()); + // Make %s print booleans as "true" and "false" + out.setf(std::ios::boolalpha); + break; + case 'n': + // Not supported - will cause problems! + TINYFORMAT_ERROR("tinyformat: %n conversion spec not supported"); + break; + case '\0': + TINYFORMAT_ERROR("tinyformat: Conversion spec incorrectly " + "terminated by end of string"); + return c; + default: + break; + } + if(intConversion && precisionSet && !widthSet) + { + // "precision" for integers gives the minimum number of digits (to be + // padded with zeros on the left). This isn't really supported by the + // iostreams, but we can approximately simulate it with the width if + // the width isn't otherwise used. + out.width(out.precision() + widthExtra); + out.setf(std::ios::internal, std::ios::adjustfield); + out.fill('0'); + } + return c+1; +} + + +//------------------------------------------------------------------------------ +inline void formatImpl(std::ostream& out, const char* fmt, + const detail::FormatArg* formatters, + int numFormatters) +{ + // Saved stream state + std::streamsize origWidth = out.width(); + std::streamsize origPrecision = out.precision(); + std::ios::fmtflags origFlags = out.flags(); + char origFill = out.fill(); + + for (int argIndex = 0; argIndex < numFormatters; ++argIndex) + { + // Parse the format string + fmt = printFormatStringLiteral(out, fmt); + bool spacePadPositive = false; + int ntrunc = -1; + const char* fmtEnd = streamStateFromFormat(out, spacePadPositive, ntrunc, fmt, + formatters, argIndex, numFormatters); + if (argIndex >= numFormatters) + { + // Check args remain after reading any variable width/precision + TINYFORMAT_ERROR("tinyformat: Not enough format arguments"); + return; + } + const FormatArg& arg = formatters[argIndex]; + // Format the arg into the stream. + if(!spacePadPositive) + arg.format(out, fmt, fmtEnd, ntrunc); + else + { + // The following is a special case with no direct correspondence + // between stream formatting and the printf() behaviour. Simulate + // it crudely by formatting into a temporary string stream and + // munging the resulting string. + std::ostringstream tmpStream; + tmpStream.copyfmt(out); + tmpStream.setf(std::ios::showpos); + arg.format(tmpStream, fmt, fmtEnd, ntrunc); + std::string result = tmpStream.str(); // allocates... yuck. + for(size_t i = 0, iend = result.size(); i < iend; ++i) + if(result[i] == '+') result[i] = ' '; + out << result; + } + fmt = fmtEnd; + } + + // Print remaining part of format string. + fmt = printFormatStringLiteral(out, fmt); + if(*fmt != '\0') + TINYFORMAT_ERROR("tinyformat: Too many conversion specifiers in format string"); + + // Restore stream state + out.width(origWidth); + out.precision(origPrecision); + out.flags(origFlags); + out.fill(origFill); +} + +} // namespace detail + + +/// List of template arguments format(), held in a type-opaque way. +/// +/// A const reference to FormatList (typedef'd as FormatListRef) may be +/// conveniently used to pass arguments to non-template functions: All type +/// information has been stripped from the arguments, leaving just enough of a +/// common interface to perform formatting as required. +class FormatList +{ + public: + FormatList(detail::FormatArg* formatters, int N) + : m_formatters(formatters), m_N(N) { } + + friend void vformat(std::ostream& out, const char* fmt, + const FormatList& list); + + private: + const detail::FormatArg* m_formatters; + int m_N; +}; + +/// Reference to type-opaque format list for passing to vformat() +typedef const FormatList& FormatListRef; + + +namespace detail { + +// Format list subclass with fixed storage to avoid dynamic allocation +template +class FormatListN : public FormatList +{ + public: +#ifdef TINYFORMAT_USE_VARIADIC_TEMPLATES + template + FormatListN(const Args&... args) + : FormatList(&m_formatterStore[0], N), + m_formatterStore { FormatArg(args)... } + { static_assert(sizeof...(args) == N, "Number of args must be N"); } +#else // C++98 version + void init(int) {} +# define TINYFORMAT_MAKE_FORMATLIST_CONSTRUCTOR(n) \ + \ + template \ + FormatListN(TINYFORMAT_VARARGS(n)) \ + : FormatList(&m_formatterStore[0], n) \ + { assert(n == N); init(0, TINYFORMAT_PASSARGS(n)); } \ + \ + template \ + void init(int i, TINYFORMAT_VARARGS(n)) \ + { \ + m_formatterStore[i] = FormatArg(v1); \ + init(i+1 TINYFORMAT_PASSARGS_TAIL(n)); \ + } + + TINYFORMAT_FOREACH_ARGNUM(TINYFORMAT_MAKE_FORMATLIST_CONSTRUCTOR) +# undef TINYFORMAT_MAKE_FORMATLIST_CONSTRUCTOR +#endif + + private: + FormatArg m_formatterStore[N]; +}; + +// Special 0-arg version - MSVC says zero-sized C array in struct is nonstandard +template<> class FormatListN<0> : public FormatList +{ + public: FormatListN() : FormatList(0, 0) {} +}; + +} // namespace detail + + +//------------------------------------------------------------------------------ +// Primary API functions + +#ifdef TINYFORMAT_USE_VARIADIC_TEMPLATES + +/// Make type-agnostic format list from list of template arguments. +/// +/// The exact return type of this function is an implementation detail and +/// shouldn't be relied upon. Instead it should be stored as a FormatListRef: +/// +/// FormatListRef formatList = makeFormatList( /*...*/ ); +template +detail::FormatListN makeFormatList(const Args&... args) +{ + return detail::FormatListN(args...); +} + +#else // C++98 version + +inline detail::FormatListN<0> makeFormatList() +{ + return detail::FormatListN<0>(); +} +#define TINYFORMAT_MAKE_MAKEFORMATLIST(n) \ +template \ +detail::FormatListN makeFormatList(TINYFORMAT_VARARGS(n)) \ +{ \ + return detail::FormatListN(TINYFORMAT_PASSARGS(n)); \ +} +TINYFORMAT_FOREACH_ARGNUM(TINYFORMAT_MAKE_MAKEFORMATLIST) +#undef TINYFORMAT_MAKE_MAKEFORMATLIST + +#endif + +/// Format list of arguments to the stream according to the given format string. +/// +/// The name vformat() is chosen for the semantic similarity to vprintf(): the +/// list of format arguments is held in a single function argument. +inline void vformat(std::ostream& out, const char* fmt, FormatListRef list) +{ + detail::formatImpl(out, fmt, list.m_formatters, list.m_N); +} + + +#ifdef TINYFORMAT_USE_VARIADIC_TEMPLATES + +/// Format list of arguments to the stream according to given format string. +template +void format(std::ostream& out, const char* fmt, const Args&... args) +{ + vformat(out, fmt, makeFormatList(args...)); +} + +/// Format list of arguments according to the given format string and return +/// the result as a string. +template +std::string format(const char* fmt, const Args&... args) +{ + std::ostringstream oss; + format(oss, fmt, args...); + return oss.str(); +} + +/// Format list of arguments to std::cout, according to the given format string +template +void printf(const char* fmt, const Args&... args) +{ + format(std::cout, fmt, args...); +} + +template +void printfln(const char* fmt, const Args&... args) +{ + format(std::cout, fmt, args...); + std::cout << '\n'; +} + +#else // C++98 version + +inline void format(std::ostream& out, const char* fmt) +{ + vformat(out, fmt, makeFormatList()); +} + +inline std::string format(const char* fmt) +{ + std::ostringstream oss; + format(oss, fmt); + return oss.str(); +} + +inline void printf(const char* fmt) +{ + format(std::cout, fmt); +} + +inline void printfln(const char* fmt) +{ + format(std::cout, fmt); + std::cout << '\n'; +} + +#define TINYFORMAT_MAKE_FORMAT_FUNCS(n) \ + \ +template \ +void format(std::ostream& out, const char* fmt, TINYFORMAT_VARARGS(n)) \ +{ \ + vformat(out, fmt, makeFormatList(TINYFORMAT_PASSARGS(n))); \ +} \ + \ +template \ +std::string format(const char* fmt, TINYFORMAT_VARARGS(n)) \ +{ \ + std::ostringstream oss; \ + format(oss, fmt, TINYFORMAT_PASSARGS(n)); \ + return oss.str(); \ +} \ + \ +template \ +void printf(const char* fmt, TINYFORMAT_VARARGS(n)) \ +{ \ + format(std::cout, fmt, TINYFORMAT_PASSARGS(n)); \ +} \ + \ +template \ +void printfln(const char* fmt, TINYFORMAT_VARARGS(n)) \ +{ \ + format(std::cout, fmt, TINYFORMAT_PASSARGS(n)); \ + std::cout << '\n'; \ +} + +TINYFORMAT_FOREACH_ARGNUM(TINYFORMAT_MAKE_FORMAT_FUNCS) +#undef TINYFORMAT_MAKE_FORMAT_FUNCS + +#endif + +// Added for Bitcoin Core +template +std::string format(const std::string &fmt, const Args&... args) +{ + std::ostringstream oss; + format(oss, fmt.c_str(), args...); + return oss.str(); +} + +} // namespace tinyformat + +#define strprintf tfm::format + +#endif // TINYFORMAT_H_INCLUDED diff --git a/privacy/zsl/utils/uint256.cpp b/privacy/zsl/utils/uint256.cpp new file mode 100644 index 0000000..2514880 --- /dev/null +++ b/privacy/zsl/utils/uint256.cpp @@ -0,0 +1,146 @@ +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2009-2014 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "uint256.h" + +#include "utilstrencodings.h" + +#include +#include + +template +base_blob::base_blob(const std::vector& vch) +{ + assert(vch.size() == sizeof(data)); + memcpy(data, &vch[0], sizeof(data)); +} + +template +std::string base_blob::GetHex() const +{ + char psz[sizeof(data) * 2 + 1]; + for (unsigned int i = 0; i < sizeof(data); i++) + sprintf(psz + i * 2, "%02x", data[sizeof(data) - i - 1]); + return std::string(psz, psz + sizeof(data) * 2); +} + +template +void base_blob::SetHex(const char* psz) +{ + memset(data, 0, sizeof(data)); + + // skip leading spaces + while (isspace(*psz)) + psz++; + + // skip 0x + if (psz[0] == '0' && tolower(psz[1]) == 'x') + psz += 2; + + // hex string to uint + const char* pbegin = psz; + while (::HexDigit(*psz) != -1) + psz++; + psz--; + unsigned char* p1 = (unsigned char*)data; + unsigned char* pend = p1 + WIDTH; + while (psz >= pbegin && p1 < pend) { + *p1 = ::HexDigit(*psz--); + if (psz >= pbegin) { + *p1 |= ((unsigned char)::HexDigit(*psz--) << 4); + p1++; + } + } +} + +template +void base_blob::SetHex(const std::string& str) +{ + SetHex(str.c_str()); +} + +template +std::string base_blob::ToString() const +{ + return (GetHex()); +} + +// Explicit instantiations for base_blob<160> +template base_blob<160>::base_blob(const std::vector&); +template std::string base_blob<160>::GetHex() const; +template std::string base_blob<160>::ToString() const; +template void base_blob<160>::SetHex(const char*); +template void base_blob<160>::SetHex(const std::string&); + +// Explicit instantiations for base_blob<256> +template base_blob<256>::base_blob(const std::vector&); +template std::string base_blob<256>::GetHex() const; +template std::string base_blob<256>::ToString() const; +template void base_blob<256>::SetHex(const char*); +template void base_blob<256>::SetHex(const std::string&); + +static void inline HashMix(uint32_t& a, uint32_t& b, uint32_t& c) +{ + // Taken from lookup3, by Bob Jenkins. + a -= c; + a ^= ((c << 4) | (c >> 28)); + c += b; + b -= a; + b ^= ((a << 6) | (a >> 26)); + a += c; + c -= b; + c ^= ((b << 8) | (b >> 24)); + b += a; + a -= c; + a ^= ((c << 16) | (c >> 16)); + c += b; + b -= a; + b ^= ((a << 19) | (a >> 13)); + a += c; + c -= b; + c ^= ((b << 4) | (b >> 28)); + b += a; +} + +static void inline HashFinal(uint32_t& a, uint32_t& b, uint32_t& c) +{ + // Taken from lookup3, by Bob Jenkins. + c ^= b; + c -= ((b << 14) | (b >> 18)); + a ^= c; + a -= ((c << 11) | (c >> 21)); + b ^= a; + b -= ((a << 25) | (a >> 7)); + c ^= b; + c -= ((b << 16) | (b >> 16)); + a ^= c; + a -= ((c << 4) | (c >> 28)); + b ^= a; + b -= ((a << 14) | (a >> 18)); + c ^= b; + c -= ((b << 24) | (b >> 8)); +} + +uint64_t uint256::GetHash(const uint256& salt) const +{ + uint32_t a, b, c; + const uint32_t *pn = (const uint32_t*)data; + const uint32_t *salt_pn = (const uint32_t*)salt.data; + a = b = c = 0xdeadbeef + WIDTH; + + a += pn[0] ^ salt_pn[0]; + b += pn[1] ^ salt_pn[1]; + c += pn[2] ^ salt_pn[2]; + HashMix(a, b, c); + a += pn[3] ^ salt_pn[3]; + b += pn[4] ^ salt_pn[4]; + c += pn[5] ^ salt_pn[5]; + HashMix(a, b, c); + a += pn[6] ^ salt_pn[6]; + b += pn[7] ^ salt_pn[7]; + HashFinal(a, b, c); + + return ((((uint64_t)b) << 32) | c); +} diff --git a/privacy/zsl/utils/uint256.h b/privacy/zsl/utils/uint256.h new file mode 100644 index 0000000..f22a8ba --- /dev/null +++ b/privacy/zsl/utils/uint256.h @@ -0,0 +1,162 @@ +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2009-2014 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_UINT256_H +#define BITCOIN_UINT256_H + +#include +#include +#include +#include +#include +#include + +/** Template base class for fixed-sized opaque blobs. */ +template +class base_blob +{ +protected: + enum { WIDTH=BITS/8 }; + alignas(uint32_t) uint8_t data[WIDTH]; +public: + base_blob() + { + memset(data, 0, sizeof(data)); + } + + explicit base_blob(const std::vector& vch); + + bool IsNull() const + { + for (int i = 0; i < WIDTH; i++) + if (data[i] != 0) + return false; + return true; + } + + void SetNull() + { + memset(data, 0, sizeof(data)); + } + + friend inline bool operator==(const base_blob& a, const base_blob& b) { return memcmp(a.data, b.data, sizeof(a.data)) == 0; } + friend inline bool operator!=(const base_blob& a, const base_blob& b) { return memcmp(a.data, b.data, sizeof(a.data)) != 0; } + friend inline bool operator<(const base_blob& a, const base_blob& b) { return memcmp(a.data, b.data, sizeof(a.data)) < 0; } + + std::string GetHex() const; + void SetHex(const char* psz); + void SetHex(const std::string& str); + std::string ToString() const; + + unsigned char* begin() + { + return &data[0]; + } + + unsigned char* end() + { + return &data[WIDTH]; + } + + const unsigned char* begin() const + { + return &data[0]; + } + + const unsigned char* end() const + { + return &data[WIDTH]; + } + + unsigned int size() const + { + return sizeof(data); + } + + template + void Serialize(Stream& s) const + { + s.write((char*)data, sizeof(data)); + } + + template + void Unserialize(Stream& s) + { + s.read((char*)data, sizeof(data)); + } +}; + +/** 88-bit opaque blob. + */ +class blob88 : public base_blob<88> { +public: + blob88() {} + blob88(const base_blob<88>& b) : base_blob<88>(b) {} + explicit blob88(const std::vector& vch) : base_blob<88>(vch) {} +}; + +/** 160-bit opaque blob. + * @note This type is called uint160 for historical reasons only. It is an opaque + * blob of 160 bits and has no integer operations. + */ +class uint160 : public base_blob<160> { +public: + uint160() {} + uint160(const base_blob<160>& b) : base_blob<160>(b) {} + explicit uint160(const std::vector& vch) : base_blob<160>(vch) {} +}; + +/** 256-bit opaque blob. + * @note This type is called uint256 for historical reasons only. It is an + * opaque blob of 256 bits and has no integer operations. Use arith_uint256 if + * those are required. + */ +class uint256 : public base_blob<256> { +public: + uint256() {} + uint256(const base_blob<256>& b) : base_blob<256>(b) {} + explicit uint256(const std::vector& vch) : base_blob<256>(vch) {} + + /** A cheap hash function that just returns 64 bits from the result, it can be + * used when the contents are considered uniformly random. It is not appropriate + * when the value can easily be influenced from outside as e.g. a network adversary could + * provide values to trigger worst-case behavior. + * @note The result of this function is not stable between little and big endian. + */ + uint64_t GetCheapHash() const + { + uint64_t result; + memcpy((void*)&result, (void*)data, 8); + return result; + } + + /** A more secure, salted hash function. + * @note This hash is not stable between little and big endian. + */ + uint64_t GetHash(const uint256& salt) const; +}; + +/* uint256 from const char *. + * This is a separate function because the constructor uint256(const char*) can result + * in dangerously catching uint256(0). + */ +inline uint256 uint256S(const char *str) +{ + uint256 rv; + rv.SetHex(str); + return rv; +} +/* uint256 from std::string. + * This is a separate function because the constructor uint256(const std::string &str) can result + * in dangerously catching uint256(0) via std::string(const char*). + */ +inline uint256 uint256S(const std::string& str) +{ + uint256 rv; + rv.SetHex(str); + return rv; +} + +#endif // BITCOIN_UINT256_H diff --git a/privacy/zsl/utils/util.cpp b/privacy/zsl/utils/util.cpp new file mode 100644 index 0000000..3a928a8 --- /dev/null +++ b/privacy/zsl/utils/util.cpp @@ -0,0 +1,307 @@ +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "util.h" + + +void printChar(const unsigned char c) { + for(int j = 8; j >= 0; j--) { + std::cout << ((c >> j) & 1); + } + std::cout << std::endl; +} + +void printVector(const std::vector& v) { + std::cout << v.size() << " MSB "; + for(size_t i = 0; i < v.size(); i++) { + std::cout << v.at(i); + } + std::cout << " LSB" << std::endl; +} + +void printVector(const std::string str, const std::vector& v) { + std::cout << str << " " << v.size() << " MSB "; + for(size_t i = 0; i < v.size(); i++) { + std::cout << v.at(i); + } + std::cout << " LSB" << std::endl; +} + +void printVectorAsHex(const std::vector& v) { + unsigned char bytes[int(v.size() / 8)]; + convertVectorToBytes(v, bytes); + + for(int i = 0; i < int(v.size() / 8); i++) { + std::cout << std::setw(2) << std::setfill('0') << std::hex << (int) bytes[i]; + } + std::cout << std::dec << std::endl; +} + +void printVectorAsHex(const std::string str, const std::vector& v) { + unsigned char bytes[int(v.size() / 8)]; + convertVectorToBytes(v, bytes); + + std::cout << str << " "; + for(int i = 0; i < int(v.size() / 8); i++) { + std::cout << std::setw(2) << std::setfill('0') << std::hex << (int) bytes[i]; + } + std::cout << std::dec << std::endl; +} + +void printBytesVector(const std::vector& v) { + std::vector boolVec(v.size() * 8); + convertBytesVectorToVector(v, boolVec); + printVector(boolVec); +} + +void printBytesVector(const std::string str, const std::vector& v) { + std::vector boolVec(v.size() * 8); + convertBytesVectorToVector(v, boolVec); + printVector(str, boolVec); +} + +void printBytesVectorAsHex(const std::vector& v) { + std::vector boolVec(v.size() * 8); + convertBytesVectorToVector(v, boolVec); + printVectorAsHex(boolVec); +} + +void printBytesVectorAsHex(const std::string str, const std::vector& v) { + std::vector boolVec(v.size() * 8); + convertBytesVectorToVector(v, boolVec); + printVectorAsHex(str, boolVec); +} + +void getRandBytes(unsigned char* bytes, int num) { + int ret = RAND_bytes(bytes, num); + if(ret != 1) + std::cout << "rand_bytes error!" << ERR_get_error() << std::endl; +} + +void convertBytesToVector(const unsigned char* bytes, std::vector& v) { + int numBytes = v.size() / 8; + unsigned char c; + for(int i = 0; i < numBytes; i++) { + c = bytes[i]; + + for(int j = 0; j < 8; j++) { + v.at((i*8)+j) = ((c >> (7-j)) & 1); + } + } +} + +void convertVectorToBytes(const std::vector& v, unsigned char* bytes) { + int numBytes = v.size() / 8; + unsigned char c = '\0'; + + for(int i = 0; i < numBytes; i++) { + c = '\0'; + for(int j = 0; j < 8; j++) { + if(j == 7) + c = ((c | v.at((i*8)+j))); + else + c = ((c | v.at((i*8)+j)) << 1); + } + bytes[i] = c; + } +} + +void convertBytesToBytesVector(const unsigned char* bytes, std::vector& v) { + for(size_t i = 0; i < v.size(); i++) { + v.at(i) = bytes[i]; + } +} + +void convertBytesVectorToBytes(const std::vector& v, unsigned char* bytes) { + for(size_t i = 0; i < v.size(); i++) { + bytes[i] = v.at(i); + } +} + +void convertBytesVectorToVector(const std::vector& bytes, std::vector& v) { + v.resize(bytes.size() * 8); + unsigned char bytesArr[bytes.size()]; + convertBytesVectorToBytes(bytes, bytesArr); + convertBytesToVector(bytesArr, v); +} + +void convertVectorToBytesVector(const std::vector& v, std::vector& bytes) { + unsigned char bytesArr[int(ceil(v.size() / 8.))]; + convertVectorToBytes(v, bytesArr); + convertBytesToBytesVector(bytesArr, bytes); +} + +void convertIntToBytesVector(const uint64_t val_int, std::vector& bytes) { + for(size_t i = 0; i < bytes.size(); i++) { + bytes[bytes.size()-1-i] = (val_int >> (i * 8)); + } +} + +uint64_t convertBytesVectorToInt(const std::vector& bytes) { + uint64_t val_int = 0; + + for(size_t i = 0; i < bytes.size(); i++) { + val_int = val_int + (bytes[i] << ((bytes.size()-1-i) * 8)); + } + + return val_int; +} + +void concatenateVectors(const std::vector& A, const std::vector& B, std::vector& result) { + result.reserve(A.size() + B.size()); + result.insert(result.end(), A.begin(), A.end()); + result.insert(result.end(), B.begin(), B.end()); +} + +void concatenateVectors(const std::vector& A, const std::vector& B, std::vector& result) { + result.reserve(A.size() + B.size()); + result.insert(result.end(), A.begin(), A.end()); + result.insert(result.end(), B.begin(), B.end()); +} + +void concatenateVectors(const std::vector& A, const std::vector& B, const std::vector& C, std::vector& result) { + result.reserve(A.size() + B.size() + C.size()); + result.insert(result.end(), A.begin(), A.end()); + result.insert(result.end(), B.begin(), B.end()); + result.insert(result.end(), C.begin(), C.end()); +} + +void concatenateVectors(const std::vector& A, const std::vector& B, const std::vector& C, std::vector& result) { + result.reserve(A.size() + B.size() + C.size()); + result.insert(result.end(), A.begin(), A.end()); + result.insert(result.end(), B.begin(), B.end()); + result.insert(result.end(), C.begin(), C.end()); +} + +void sha256(unsigned char* input, unsigned char* hash, int len) { + SHA256_CTX_mod ctx256; + + sha256_init(&ctx256); + sha256_update(&ctx256, input, len); + sha256_final(&ctx256, hash); +} + +void sha256(SHA256_CTX_mod* ctx256, unsigned char* input, unsigned char* hash, int len) { + sha256_init(ctx256); + sha256_update(ctx256, input, len); + sha256_final(ctx256, hash); +} + +void hashVector(SHA256_CTX_mod* ctx256, const std::vector input, std::vector& output) { + int size = int(input.size() / 8); + unsigned char bytes[size]; + convertVectorToBytes(input, bytes); + + unsigned char hash[SHA256_BLOCK_SIZE]; + sha256(ctx256, bytes, hash, (int)size); + + convertBytesToVector(hash, output); +} + +void hashVector(SHA256_CTX_mod* ctx256, const std::vector input, std::vector& output) { + int size = int(input.size()); + unsigned char bytes[size]; + convertBytesVectorToBytes(input, bytes); + + unsigned char hash[SHA256_BLOCK_SIZE]; + sha256(ctx256, bytes, hash, (int)size); + + convertBytesToBytesVector(hash, output); +} + +void hashVector(const std::vector input, std::vector& output) { + SHA256_CTX_mod ctx256; + + int size = int(input.size() / 8); + unsigned char bytes[size]; + convertVectorToBytes(input, bytes); + + unsigned char hash[SHA256_BLOCK_SIZE]; + sha256(&ctx256, bytes, hash, (int)size); + + convertBytesToVector(hash, output); +} + +void hashVector(const std::vector input, std::vector& output) { + SHA256_CTX_mod ctx256; + + int size = int(input.size()); + unsigned char bytes[size]; + convertBytesVectorToBytes(input, bytes); + + unsigned char hash[SHA256_BLOCK_SIZE]; + sha256(&ctx256, bytes, hash, (int)size); + + convertBytesToBytesVector(hash, output); +} + +void hashVectors(SHA256_CTX_mod* ctx256, const std::vector left, const std::vector right, std::vector& output) { + std::vector concat; + concatenateVectors(left, right, concat); + + int size = int(concat.size() / 8); + unsigned char bytes[size]; + convertVectorToBytes(concat, bytes); + + unsigned char hash[SHA256_BLOCK_SIZE]; + sha256(ctx256, bytes, hash, (int)size); + + convertBytesToVector(hash, output); +} + +void hashVectors(SHA256_CTX_mod* ctx256, const std::vector left, const std::vector right, std::vector& output) { + std::vector concat; + concatenateVectors(left, right, concat); + + int size = int(concat.size()); + unsigned char bytes[size]; + convertBytesVectorToBytes(concat, bytes); + + unsigned char hash[SHA256_BLOCK_SIZE]; + sha256(ctx256, bytes, hash, (int)size); + + convertBytesToBytesVector(hash, output); +} + +void hashVectors(const std::vector left, const std::vector right, std::vector& output) { + std::cout << std::endl; + + std::vector concat; + concatenateVectors(left, right, concat); + + int size = int(concat.size() / 8); + unsigned char bytes[size]; + convertVectorToBytes(concat, bytes); + + unsigned char hash[SHA256_BLOCK_SIZE]; + sha256(bytes, hash, (int)size); + + convertBytesToVector(hash, output); +} + +void hashVectors(const std::vector left, const std::vector right, std::vector& output) { + std::vector concat; + concatenateVectors(left, right, concat); + + int size = int(concat.size()); + unsigned char bytes[size]; + convertBytesVectorToBytes(concat, bytes); + + unsigned char hash[SHA256_BLOCK_SIZE]; + sha256(bytes, hash, (int)size); + + convertBytesToBytesVector(hash, output); +} + +bool VectorIsZero(const std::vector test) { + return (test.end() == std::find(test.begin(), test.end(), true)); +} diff --git a/privacy/zsl/utils/util.h b/privacy/zsl/utils/util.h new file mode 100644 index 0000000..24405a9 --- /dev/null +++ b/privacy/zsl/utils/util.h @@ -0,0 +1,78 @@ +#ifndef UTIL_H_ +#define UTIL_H_ + +#include +#include + +#include "sha256.h" +#include "uint256.h" + +void printChar(const unsigned char c); + +void printVector(const std::vector& v); + +void printVector(const std::string str, const std::vector& v); + +void printVectorAsHex(const std::vector& v); + +void printVectorAsHex(const std::string str, const std::vector& v); + +void printBytesVector(const std::vector& v); + +void printBytesVector(const std::string str, const std::vector& v); + +void printBytesVectorAsHex(const std::vector& v); + +void printBytesVectorAsHex(const std::string str, const std::vector& v); + +void getRandBytes(unsigned char* bytes, int num); + +void convertBytesToVector(const unsigned char* bytes, std::vector& v); + +void convertVectorToBytes(const std::vector& v, unsigned char* bytes); + +void convertBytesToBytesVector(const unsigned char* bytes, std::vector& v); + +void convertBytesVectorToBytes(const std::vector& v, unsigned char* bytes); + +void convertBytesVectorToVector(const std::vector& bytes, std::vector& v); + +void convertVectorToBytesVector(const std::vector& v, std::vector& bytes); + +void convertIntToBytesVector(const uint64_t val_int, std::vector& bytes); + +uint64_t convertBytesVectorToInt(const std::vector& bytes); + +void concatenateVectors(const std::vector& A, const std::vector& B, std::vector& result); + +void concatenateVectors(const std::vector& A, const std::vector& B, std::vector& result); + +void concatenateVectors(const std::vector& A, const std::vector& B, const std::vector& C, std::vector& result); + +void concatenateVectors(const std::vector& A, const std::vector& B, const std::vector& C, std::vector& result); + +void sha256(unsigned char* input, unsigned char* hash, int len); + +void sha256(SHA256_CTX_mod* ctx256, unsigned char* input, unsigned char* hash, int len); + +void hashVector(SHA256_CTX_mod* ctx256, const std::vector input, std::vector& output); + +void hashVector(SHA256_CTX_mod* ctx256, const std::vector input, std::vector& output); + +void hashVector(const std::vector input, std::vector& output); + +void hashVector(const std::vector input, std::vector& output); + +void hashVectors(SHA256_CTX_mod* ctx256, const std::vector left, const std::vector right, std::vector& output); + +void hashVectors(SHA256_CTX_mod* ctx256, const std::vector left, const std::vector right, std::vector& output); + +void hashVectors(const std::vector left, const std::vector right, std::vector& output); + +void hashVectors(const std::vector left, const std::vector right, std::vector& output); + +bool VectorIsZero(const std::vector test); + +#endif /* UTIL_H_ */ + + diff --git a/privacy/zsl/utils/utilstrencodings.cpp b/privacy/zsl/utils/utilstrencodings.cpp new file mode 100644 index 0000000..ece2ec7 --- /dev/null +++ b/privacy/zsl/utils/utilstrencodings.cpp @@ -0,0 +1,506 @@ +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2009-2014 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "utilstrencodings.h" + +#include "tinyformat.h" + +#include +#include +#include +#include +#include + +using namespace std; + +static const string CHARS_ALPHA_NUM = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; + +static const string SAFE_CHARS[] = +{ + CHARS_ALPHA_NUM + " .,;_/:?@()", // SAFE_CHARS_DEFAULT + CHARS_ALPHA_NUM + " .,;_?@" // SAFE_CHARS_UA_COMMENT +}; + +string SanitizeString(const string& str, int rule) +{ + string strResult; + for (std::string::size_type i = 0; i < str.size(); i++) + { + if (SAFE_CHARS[rule].find(str[i]) != std::string::npos) + strResult.push_back(str[i]); + } + return strResult; +} + +string SanitizeFilename(const string& str) +{ + /** + * safeChars chosen to restrict filename, keeping it simple to avoid cross-platform issues. + * http://stackoverflow.com/a/2306003 + */ + static string safeChars("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890"); + string strResult; + for (std::string::size_type i = 0; i < str.size(); i++) + { + if (safeChars.find(str[i]) != std::string::npos) + strResult.push_back(str[i]); + } + return strResult; +} + +std::string HexInt(uint32_t val) +{ + std::stringstream ss; + ss << std::setfill('0') << std::setw(sizeof(uint32_t) * 2) << std::hex << val; + return ss.str(); +} + +uint32_t ParseHexToUInt32(const std::string& str) { + std::istringstream converter(str); + uint32_t value; + converter >> std::hex >> value; + return value; +} + +const signed char p_util_hexdigit[256] = +{ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + 0,1,2,3,4,5,6,7,8,9,-1,-1,-1,-1,-1,-1, + -1,0xa,0xb,0xc,0xd,0xe,0xf,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,0xa,0xb,0xc,0xd,0xe,0xf,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, }; + +signed char HexDigit(char c) +{ + return p_util_hexdigit[(unsigned char)c]; +} + +bool IsHex(const string& str) +{ + for(std::string::const_iterator it(str.begin()); it != str.end(); ++it) + { + if (HexDigit(*it) < 0) + return false; + } + return (str.size() > 0) && (str.size()%2 == 0); +} + +vector ParseHex(const char* psz) +{ + // convert hex dump to vector + vector vch; + while (true) + { + while (isspace(*psz)) + psz++; + signed char c = HexDigit(*psz++); + if (c == (signed char)-1) + break; + unsigned char n = (c << 4); + c = HexDigit(*psz++); + if (c == (signed char)-1) + break; + n |= c; + vch.push_back(n); + } + return vch; +} + +vector ParseHex(const string& str) +{ + return ParseHex(str.c_str()); +} + +string EncodeBase64(const unsigned char* pch, size_t len) +{ + static const char *pbase64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + + std::string str; + str.reserve(((len + 2) / 3) * 4); + ConvertBits<8, 6, true>([&](int v) { str += pbase64[v]; }, pch, pch + len); + while (str.size() % 4) str += '='; + return str; +} + +string EncodeBase64(const string& str) +{ + return EncodeBase64((const unsigned char*)str.c_str(), str.size()); +} + +vector DecodeBase64(const char* p, bool* pfInvalid) +{ + static const int decode64_table[256] = + { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, + -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, -1, 26, 27, 28, + 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 + }; + + const char* e = p; + std::vector val; + val.reserve(strlen(p)); + while (*p != 0) { + int x = decode64_table[(unsigned char)*p]; + if (x == -1) break; + val.push_back(x); + ++p; + } + + std::vector ret; + ret.reserve((val.size() * 3) / 4); + bool valid = ConvertBits<6, 8, false>([&](unsigned char c) { ret.push_back(c); }, val.begin(), val.end()); + + const char* q = p; + while (valid && *p != 0) { + if (*p != '=') { + valid = false; + break; + } + ++p; + } + valid = valid && (p - e) % 4 == 0 && p - q < 4; + if (pfInvalid) *pfInvalid = !valid; + + return ret; +} + +string DecodeBase64(const string& str) +{ + vector vchRet = DecodeBase64(str.c_str()); + return (vchRet.size() == 0) ? string() : string((const char*)&vchRet[0], vchRet.size()); +} + +string EncodeBase32(const unsigned char* pch, size_t len) +{ + static const char *pbase32 = "abcdefghijklmnopqrstuvwxyz234567"; + + std::string str; + str.reserve(((len + 4) / 5) * 8); + ConvertBits<8, 5, true>([&](int v) { str += pbase32[v]; }, pch, pch + len); + while (str.size() % 8) str += '='; + return str; +} + +string EncodeBase32(const string& str) +{ + return EncodeBase32((const unsigned char*)str.c_str(), str.size()); +} + +vector DecodeBase32(const char* p, bool* pfInvalid) +{ + static const int decode32_table[256] = + { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, -1, 0, 1, 2, + 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, + 23, 24, 25, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 + }; + + const char* e = p; + std::vector val; + val.reserve(strlen(p)); + while (*p != 0) { + int x = decode32_table[(unsigned char)*p]; + if (x == -1) break; + val.push_back(x); + ++p; + } + + std::vector ret; + ret.reserve((val.size() * 5) / 8); + bool valid = ConvertBits<5, 8, false>([&](unsigned char c) { ret.push_back(c); }, val.begin(), val.end()); + + const char* q = p; + while (valid && *p != 0) { + if (*p != '=') { + valid = false; + break; + } + ++p; + } + valid = valid && (p - e) % 8 == 0 && p - q < 8; + if (pfInvalid) *pfInvalid = !valid; + + return ret; +} + +string DecodeBase32(const string& str) +{ + vector vchRet = DecodeBase32(str.c_str()); + return (vchRet.size() == 0) ? string() : string((const char*)&vchRet[0], vchRet.size()); +} + +static bool ParsePrechecks(const std::string& str) +{ + if (str.empty()) // No empty string allowed + return false; + if (str.size() >= 1 && (isspace(str[0]) || isspace(str[str.size()-1]))) // No padding allowed + return false; + if (str.size() != strlen(str.c_str())) // No embedded NUL characters allowed + return false; + return true; +} + +bool ParseInt32(const std::string& str, int32_t *out) +{ + if (!ParsePrechecks(str)) + return false; + char *endp = NULL; + errno = 0; // strtol will not set errno if valid + long int n = strtol(str.c_str(), &endp, 10); + if(out) *out = (int32_t)n; + // Note that strtol returns a *long int*, so even if strtol doesn't report a over/underflow + // we still have to check that the returned value is within the range of an *int32_t*. On 64-bit + // platforms the size of these types may be different. + return endp && *endp == 0 && !errno && + n >= std::numeric_limits::min() && + n <= std::numeric_limits::max(); +} + +bool ParseInt64(const std::string& str, int64_t *out) +{ + if (!ParsePrechecks(str)) + return false; + char *endp = NULL; + errno = 0; // strtoll will not set errno if valid + long long int n = strtoll(str.c_str(), &endp, 10); + if(out) *out = (int64_t)n; + // Note that strtoll returns a *long long int*, so even if strtol doesn't report a over/underflow + // we still have to check that the returned value is within the range of an *int64_t*. + return endp && *endp == 0 && !errno && + n >= std::numeric_limits::min() && + n <= std::numeric_limits::max(); +} + +bool ParseDouble(const std::string& str, double *out) +{ + if (!ParsePrechecks(str)) + return false; + if (str.size() >= 2 && str[0] == '0' && str[1] == 'x') // No hexadecimal floats allowed + return false; + std::istringstream text(str); + text.imbue(std::locale::classic()); + double result; + text >> result; + if(out) *out = result; + return text.eof() && !text.fail(); +} + +std::string FormatParagraph(const std::string& in, size_t width, size_t indent) +{ + std::stringstream out; + size_t col = 0; + size_t ptr = 0; + while(ptr < in.size()) + { + // Find beginning of next word + ptr = in.find_first_not_of(' ', ptr); + if (ptr == std::string::npos) + break; + // Find end of next word + size_t endword = in.find_first_of(' ', ptr); + if (endword == std::string::npos) + endword = in.size(); + // Add newline and indentation if this wraps over the allowed width + if (col > 0) + { + if ((col + endword - ptr) > width) + { + out << '\n'; + for(size_t i=0; i (UPPER_BOUND / 10LL)) + return false; /* overflow */ + mantissa *= 10; + } + mantissa += ch - '0'; + mantissa_tzeros = 0; + } + return true; +} + +bool ParseFixedPoint(const std::string &val, int decimals, int64_t *amount_out) +{ + int64_t mantissa = 0; + int64_t exponent = 0; + int mantissa_tzeros = 0; + bool mantissa_sign = false; + bool exponent_sign = false; + int ptr = 0; + int end = val.size(); + int point_ofs = 0; + + if (ptr < end && val[ptr] == '-') { + mantissa_sign = true; + ++ptr; + } + if (ptr < end) + { + if (val[ptr] == '0') { + /* pass single 0 */ + ++ptr; + } else if (val[ptr] >= '1' && val[ptr] <= '9') { + while (ptr < end && val[ptr] >= '0' && val[ptr] <= '9') { + if (!ProcessMantissaDigit(val[ptr], mantissa, mantissa_tzeros)) + return false; /* overflow */ + ++ptr; + } + } else return false; /* missing expected digit */ + } else return false; /* empty string or loose '-' */ + if (ptr < end && val[ptr] == '.') + { + ++ptr; + if (ptr < end && val[ptr] >= '0' && val[ptr] <= '9') + { + while (ptr < end && val[ptr] >= '0' && val[ptr] <= '9') { + if (!ProcessMantissaDigit(val[ptr], mantissa, mantissa_tzeros)) + return false; /* overflow */ + ++ptr; + ++point_ofs; + } + } else return false; /* missing expected digit */ + } + if (ptr < end && (val[ptr] == 'e' || val[ptr] == 'E')) + { + ++ptr; + if (ptr < end && val[ptr] == '+') + ++ptr; + else if (ptr < end && val[ptr] == '-') { + exponent_sign = true; + ++ptr; + } + if (ptr < end && val[ptr] >= '0' && val[ptr] <= '9') { + while (ptr < end && val[ptr] >= '0' && val[ptr] <= '9') { + if (exponent > (UPPER_BOUND / 10LL)) + return false; /* overflow */ + exponent = exponent * 10 + val[ptr] - '0'; + ++ptr; + } + } else return false; /* missing expected digit */ + } + if (ptr != end) + return false; /* trailing garbage */ + + /* finalize exponent */ + if (exponent_sign) + exponent = -exponent; + exponent = exponent - point_ofs + mantissa_tzeros; + + /* finalize mantissa */ + if (mantissa_sign) + mantissa = -mantissa; + + /* convert to one 64-bit fixed-point value */ + exponent += decimals; + if (exponent < 0) + return false; /* cannot represent values smaller than 10^-decimals */ + if (exponent >= 18) + return false; /* cannot represent values larger than or equal to 10^(18-decimals) */ + + for (int i=0; i < exponent; ++i) { + if (mantissa > (UPPER_BOUND / 10LL) || mantissa < -(UPPER_BOUND / 10LL)) + return false; /* overflow */ + mantissa *= 10; + } + if (mantissa > UPPER_BOUND || mantissa < -UPPER_BOUND) + return false; /* overflow */ + + if (amount_out) + *amount_out = mantissa; + + return true; +} + diff --git a/privacy/zsl/utils/utilstrencodings.h b/privacy/zsl/utils/utilstrencodings.h new file mode 100644 index 0000000..37a07ea --- /dev/null +++ b/privacy/zsl/utils/utilstrencodings.h @@ -0,0 +1,169 @@ +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2009-2014 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +/** + * Utilities for converting data from/to strings. + */ +#ifndef BITCOIN_UTILSTRENCODINGS_H +#define BITCOIN_UTILSTRENCODINGS_H + +#include +#include +#include + +#define BEGIN(a) ((char*)&(a)) +#define END(a) ((char*)&((&(a))[1])) +#define UBEGIN(a) ((unsigned char*)&(a)) +#define UEND(a) ((unsigned char*)&((&(a))[1])) +#define ARRAYLEN(array) (sizeof(array)/sizeof((array)[0])) + +/** This is needed because the foreach macro can't get over the comma in pair */ +#define PAIRTYPE(t1, t2) std::pair + +/** Used by SanitizeString() */ +enum SafeChars +{ + SAFE_CHARS_DEFAULT, //!< The full set of allowed chars + SAFE_CHARS_UA_COMMENT //!< BIP-0014 subset +}; + +std::string SanitizeFilename(const std::string& str); +/** +* Remove unsafe chars. Safe chars chosen to allow simple messages/URLs/email +* addresses, but avoid anything even possibly remotely dangerous like & or > +* @param[in] str The string to sanitize +* @param[in] rule The set of safe chars to choose (default: least restrictive) +* @return A new string without unsafe chars +*/ +std::string SanitizeString(const std::string& str, int rule = SAFE_CHARS_DEFAULT); +std::string HexInt(uint32_t val); +uint32_t ParseHexToUInt32(const std::string& str); +std::vector ParseHex(const char* psz); +std::vector ParseHex(const std::string& str); +signed char HexDigit(char c); +bool IsHex(const std::string& str); +std::vector DecodeBase64(const char* p, bool* pfInvalid = NULL); +std::string DecodeBase64(const std::string& str); +std::string EncodeBase64(const unsigned char* pch, size_t len); +std::string EncodeBase64(const std::string& str); +std::vector DecodeBase32(const char* p, bool* pfInvalid = NULL); +std::string DecodeBase32(const std::string& str); +std::string EncodeBase32(const unsigned char* pch, size_t len); +std::string EncodeBase32(const std::string& str); + +std::string i64tostr(int64_t n); +std::string itostr(int n); +int64_t atoi64(const char* psz); +int64_t atoi64(const std::string& str); +int atoi(const std::string& str); + +/** + * Convert string to signed 32-bit integer with strict parse error feedback. + * @returns true if the entire string could be parsed as valid integer, + * false if not the entire string could be parsed or when overflow or underflow occurred. + */ +bool ParseInt32(const std::string& str, int32_t *out); + +/** + * Convert string to signed 64-bit integer with strict parse error feedback. + * @returns true if the entire string could be parsed as valid integer, + * false if not the entire string could be parsed or when overflow or underflow occurred. + */ +bool ParseInt64(const std::string& str, int64_t *out); + +/** + * Convert string to double with strict parse error feedback. + * @returns true if the entire string could be parsed as valid double, + * false if not the entire string could be parsed or when overflow or underflow occurred. + */ +bool ParseDouble(const std::string& str, double *out); + +template +std::string HexStr(const T itbegin, const T itend, bool fSpaces=false) +{ + std::string rv; + static const char hexmap[16] = { '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; + rv.reserve((itend-itbegin)*3); + for(T it = itbegin; it < itend; ++it) + { + unsigned char val = (unsigned char)(*it); + if(fSpaces && it != itbegin) + rv.push_back(' '); + rv.push_back(hexmap[val>>4]); + rv.push_back(hexmap[val&15]); + } + + return rv; +} + +template +inline std::string HexStr(const T& vch, bool fSpaces=false) +{ + return HexStr(vch.begin(), vch.end(), fSpaces); +} + +/** + * Format a paragraph of text to a fixed width, adding spaces for + * indentation to any added line. + */ +std::string FormatParagraph(const std::string& in, size_t width = 79, size_t indent = 0); + +/** + * Timing-attack-resistant comparison. + * Takes time proportional to length + * of first argument. + */ +template +bool TimingResistantEqual(const T& a, const T& b) +{ + if (b.size() == 0) return a.size() == 0; + size_t accumulator = a.size() ^ b.size(); + for (size_t i = 0; i < a.size(); i++) + accumulator |= a[i] ^ b[i%b.size()]; + return accumulator == 0; +} + +/** Parse number as fixed point according to JSON number syntax. + * See http://json.org/number.gif + * @returns true on success, false on error. + * @note The result must be in the range (-10^18,10^18), otherwise an overflow error will trigger. + */ +bool ParseFixedPoint(const std::string &val, int decimals, int64_t *amount_out); + +/** + * Convert from one power-of-2 number base to another. + * + * Examples using ConvertBits<8, 5, true>(): + * 000000 -> 0000000000 + * 202020 -> 0400100200 + * 757575 -> 0e151a170a + * abcdef -> 150f061e1e + * ffffff -> 1f1f1f1f1e + */ +template +bool ConvertBits(const O& outfn, I it, I end) { + size_t acc = 0; + size_t bits = 0; + constexpr size_t maxv = (1 << tobits) - 1; + constexpr size_t max_acc = (1 << (frombits + tobits - 1)) - 1; + while (it != end) { + acc = ((acc << frombits) | *it) & max_acc; + bits += frombits; + while (bits >= tobits) { + bits -= tobits; + outfn((acc >> bits) & maxv); + } + ++it; + } + if (pad) { + if (bits) outfn((acc << (tobits - bits)) & maxv); + } else if (bits >= frombits || ((acc << (tobits - bits)) & maxv)) { + return false; + } + return true; +} + +#endif // BITCOIN_UTILSTRENCODINGS_H diff --git a/privacy/zsl/zsl/sha256/LICENSE b/privacy/zsl/zsl/sha256/LICENSE new file mode 100644 index 0000000..6a66aea --- /dev/null +++ b/privacy/zsl/zsl/sha256/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2009 The Go Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/privacy/zsl/zsl/sha256/PATENTS b/privacy/zsl/zsl/sha256/PATENTS new file mode 100644 index 0000000..7330990 --- /dev/null +++ b/privacy/zsl/zsl/sha256/PATENTS @@ -0,0 +1,22 @@ +Additional IP Rights Grant (Patents) + +"This implementation" means the copyrightable works distributed by +Google as part of the Go project. + +Google hereby grants to You a perpetual, worldwide, non-exclusive, +no-charge, royalty-free, irrevocable (except as stated in this section) +patent license to make, have made, use, offer to sell, sell, import, +transfer and otherwise run, modify and propagate the contents of this +implementation of Go, where such license applies only to those patent +claims, both currently owned or controlled by Google and acquired in +the future, licensable by Google that are necessarily infringed by this +implementation of Go. This grant does not include claims that would be +infringed only as a consequence of further modification of this +implementation. If you or your agent or exclusive licensee institute or +order or agree to the institution of patent litigation against any +entity (including a cross-claim or counterclaim in a lawsuit) alleging +that this implementation of Go or any code incorporated within this +implementation of Go constitutes direct or contributory patent +infringement, or inducement of patent infringement, then any patent +rights granted to you under this License for this implementation of Go +shall terminate as of the date such litigation is filed. diff --git a/privacy/zsl/zsl/sha256/README b/privacy/zsl/zsl/sha256/README new file mode 100644 index 0000000..8caff07 --- /dev/null +++ b/privacy/zsl/zsl/sha256/README @@ -0,0 +1,59 @@ +zsl/sha256 is a modified version of the crytpo/sha256 package from go 1.8.3 +https://github.com/golang/go/commits/release-branch.go1.8 + +TODO: +Move this documentation and add documentation to .go files (standard go & godoc practice) + +What's new: + +A SHA-256 compression function to apply to input data, without any padding, +which must be a 512-bit block, to produce a 256-bit hash [NIST2015]. + +Changes made: + +1. [When using Go 1.8.x] Import path to 'internal/cpu' changed in sha256block_amd64.go (BSD) to avoid import problems + with local packages in non-local packages and the special package name 'internal'. +2. Compress method added to sha256.go (BSD) +3. compress_test added (Apache) +4. [When using Go 1.8.x] Only AMD64 assembly retained, non x86 cpus removed from 'cpu' folder +5. Copied Golang LICENSE and PATENTS into package, which apply to crypto/sha256 + +Other links: + +https://github.com/zcash/zips/issues/100 + +Testing: + +Compress tests match the zcash Sha256Compress tests, run with: + +go test + + +Example usage: + +package main + +import ( + "encoding/hex" + "fmt" + + "./zsl/sha256" +) + +func main() { + buf := make([]byte, 64) + + h := sha256.New() + h.Write(buf) + result := hex.EncodeToString(h.Sum(nil)) + fmt.Println(result) + + c := sha256.NewCompress() + c.Write(buf) + + result = hex.EncodeToString(c.Sum(nil)) + fmt.Println(result) + + result = hex.EncodeToString(c.Compress()) + fmt.Println(result) +} diff --git a/privacy/zsl/zsl/sha256/compress_test.go b/privacy/zsl/zsl/sha256/compress_test.go new file mode 100644 index 0000000..bad0ee1 --- /dev/null +++ b/privacy/zsl/zsl/sha256/compress_test.go @@ -0,0 +1,100 @@ +// Copyright 2017 Zerocoin Electric Coin Company LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package sha256 + +import ( + "encoding/hex" + "testing" +) + +// Tests sha256 compress function i.e. checksum with no padding. +// https://github.com/zcash/zcash/blob/70db019c6ae989acde0a0affd6a1f1c28ec9a3d2/src/test/sha256compress_tests.cpp + +func TestCompress1(t *testing.T) { + preimage := make([]byte, 64) + h := NewCompress() + h.Write(preimage) + actual := hex.EncodeToString(h.Compress()) + expected := "da5698be17b9b46962335799779fbeca8ce5d491c0d26243bafef9ea1837a9d8" + if actual != expected { + t.Errorf("Test failed, expected: '%s', got: '%s'", expected, actual) + } +} + +func TestCompress2(t *testing.T) { + defer func() { + if r := recover(); r == nil { + t.Errorf("The code did not panic as expected") + } + }() + + preimage := make([]byte, 63) + h := NewCompress() + h.Write(preimage) + h.Compress() +} + +func TestCompress3(t *testing.T) { + defer func() { + if r := recover(); r == nil { + t.Errorf("The code did not panic as expected") + } + }() + + preimage := make([]byte, 65) + h := NewCompress() + h.Write(preimage) + h.Compress() +} + +func TestCompress4(t *testing.T) { + buf := make([]byte, 1) + h := NewCompress() + for i := 0; i < 64; i++ { + h.Write(buf) + } + actual := hex.EncodeToString(h.Compress()) + expected := "da5698be17b9b46962335799779fbeca8ce5d491c0d26243bafef9ea1837a9d8" + if actual != expected { + t.Errorf("Test failed, expected: '%s', got: '%s'", expected, actual) + } +} + +func TestCompress5(t *testing.T) { + preimage := []byte{'a', 'b', 'c', 'd', + 'a', 'b', 'c', 'd', + 'a', 'b', 'c', 'd', + 'a', 'b', 'c', 'd', + 'a', 'b', 'c', 'd', + 'a', 'b', 'c', 'd', + 'a', 'b', 'c', 'd', + 'a', 'b', 'c', 'd', + 'a', 'b', 'c', 'd', + 'a', 'b', 'c', 'd', + 'a', 'b', 'c', 'd', + 'a', 'b', 'c', 'd', + 'a', 'b', 'c', 'd', + 'a', 'b', 'c', 'd', + 'a', 'b', 'c', 'd', + 'a', 'b', 'c', 'd', + } + h := NewCompress() + h.Write(preimage) + actual := hex.EncodeToString(h.Compress()) + expected := "867d9811862dbdab2f8fa343e3e841df7db2ded433172800b0369e8741ec70da" + if actual != expected { + t.Errorf("Test failed, expected: '%s', got: '%s'", expected, actual) + } +} diff --git a/privacy/zsl/zsl/sha256/example_test.go b/privacy/zsl/zsl/sha256/example_test.go new file mode 100644 index 0000000..7d73120 --- /dev/null +++ b/privacy/zsl/zsl/sha256/example_test.go @@ -0,0 +1,41 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package sha256_test + +import ( + "crypto/sha256" + "fmt" + "io" + "log" + "os" +) + +func ExampleSum256() { + sum := sha256.Sum256([]byte("hello world\n")) + fmt.Printf("%x", sum) + // Output: a948904f2f0f479b8f8197694b30184b0d2ed1c1cd2a1ec0fb85d299a192a447 +} + +func ExampleNew() { + h := sha256.New() + h.Write([]byte("hello world\n")) + fmt.Printf("%x", h.Sum(nil)) + // Output: a948904f2f0f479b8f8197694b30184b0d2ed1c1cd2a1ec0fb85d299a192a447 +} + +func ExampleNew_file() { + f, err := os.Open("file.txt") + if err != nil { + log.Fatal(err) + } + defer f.Close() + + h := sha256.New() + if _, err := io.Copy(h, f); err != nil { + log.Fatal(err) + } + + fmt.Printf("%x", h.Sum(nil)) +} diff --git a/privacy/zsl/zsl/sha256/fallback_test.go b/privacy/zsl/zsl/sha256/fallback_test.go new file mode 100644 index 0000000..5917a48 --- /dev/null +++ b/privacy/zsl/zsl/sha256/fallback_test.go @@ -0,0 +1,35 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build s390x + +package sha256 + +import ( + "fmt" + "io" + "testing" +) + +// Tests the fallback code path in case the optimized asm +// implementation cannot be used. +// See also TestBlockGeneric. +func TestGenericPath(t *testing.T) { + if useAsm == false { + t.Skipf("assembly implementation unavailable") + } + useAsm = false + defer func() { useAsm = true }() + c := New() + in := "ΑΒΓΔΕϜΖΗΘΙΚΛΜΝΞΟΠϺϘΡΣΤΥΦΧΨΩ" + gold := "e93d84ec2b22383123be9f713697fb25" + + "338c86e2f7d8d1ddc2d89d332dd9d76c" + if _, err := io.WriteString(c, in); err != nil { + t.Fatalf("could not write to c: %v", err) + } + out := fmt.Sprintf("%x", c.Sum(nil)) + if out != gold { + t.Fatalf("mismatch: got %s, wanted %s", out, gold) + } +} diff --git a/privacy/zsl/zsl/sha256/sha256.go b/privacy/zsl/zsl/sha256/sha256.go new file mode 100644 index 0000000..0ce0657 --- /dev/null +++ b/privacy/zsl/zsl/sha256/sha256.go @@ -0,0 +1,232 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package sha256 implements the SHA224 and SHA256 hash algorithms as defined +// in FIPS 180-4. +package sha256 + +import ( + "crypto" + "hash" +) + +func init() { + crypto.RegisterHash(crypto.SHA224, New224) + crypto.RegisterHash(crypto.SHA256, New) +} + +// The size of a SHA256 checksum in bytes. +const Size = 32 + +// The size of a SHA224 checksum in bytes. +const Size224 = 28 + +// The blocksize of SHA256 and SHA224 in bytes. +const BlockSize = 64 + +const ( + chunk = 64 + init0 = 0x6A09E667 + init1 = 0xBB67AE85 + init2 = 0x3C6EF372 + init3 = 0xA54FF53A + init4 = 0x510E527F + init5 = 0x9B05688C + init6 = 0x1F83D9AB + init7 = 0x5BE0CD19 + init0_224 = 0xC1059ED8 + init1_224 = 0x367CD507 + init2_224 = 0x3070DD17 + init3_224 = 0xF70E5939 + init4_224 = 0xFFC00B31 + init5_224 = 0x68581511 + init6_224 = 0x64F98FA7 + init7_224 = 0xBEFA4FA4 +) + +// digest represents the partial evaluation of a checksum. +type digest struct { + h [8]uint32 + x [chunk]byte + nx int + len uint64 + is224 bool // mark if this digest is SHA-224 +} + +func (d *digest) Reset() { + if !d.is224 { + d.h[0] = init0 + d.h[1] = init1 + d.h[2] = init2 + d.h[3] = init3 + d.h[4] = init4 + d.h[5] = init5 + d.h[6] = init6 + d.h[7] = init7 + } else { + d.h[0] = init0_224 + d.h[1] = init1_224 + d.h[2] = init2_224 + d.h[3] = init3_224 + d.h[4] = init4_224 + d.h[5] = init5_224 + d.h[6] = init6_224 + d.h[7] = init7_224 + } + d.nx = 0 + d.len = 0 +} + +// New returns a new hash.Hash computing the SHA256 checksum. +func New() hash.Hash { + d := new(digest) + d.Reset() + return d +} + +// New224 returns a new hash.Hash computing the SHA224 checksum. +func New224() hash.Hash { + d := new(digest) + d.is224 = true + d.Reset() + return d +} + +func (d *digest) Size() int { + if !d.is224 { + return Size + } + return Size224 +} + +func (d *digest) BlockSize() int { return BlockSize } + +func (d *digest) Write(p []byte) (nn int, err error) { + nn = len(p) + d.len += uint64(nn) + if d.nx > 0 { + n := copy(d.x[d.nx:], p) + d.nx += n + if d.nx == chunk { + block(d, d.x[:]) + d.nx = 0 + } + p = p[n:] + } + if len(p) >= chunk { + n := len(p) &^ (chunk - 1) + block(d, p[:n]) + p = p[n:] + } + if len(p) > 0 { + d.nx = copy(d.x[:], p) + } + return +} + +func (d0 *digest) Sum(in []byte) []byte { + // Make a copy of d0 so that caller can keep writing and summing. + d := *d0 + hash := d.checkSum() + if d.is224 { + return append(in, hash[:Size224]...) + } + return append(in, hash[:]...) +} + +func (d *digest) checkSum() [Size]byte { + len := d.len + // Padding. Add a 1 bit and 0 bits until 56 bytes mod 64. + var tmp [64]byte + tmp[0] = 0x80 + if len%64 < 56 { + d.Write(tmp[0 : 56-len%64]) + } else { + d.Write(tmp[0 : 64+56-len%64]) + } + + // Length in bits. + len <<= 3 + for i := uint(0); i < 8; i++ { + tmp[i] = byte(len >> (56 - 8*i)) + } + d.Write(tmp[0:8]) + + if d.nx != 0 { + panic("d.nx != 0") + } + + h := d.h[:] + if d.is224 { + h = d.h[:7] + } + + var digest [Size]byte + for i, s := range h { + digest[i*4] = byte(s >> 24) + digest[i*4+1] = byte(s >> 16) + digest[i*4+2] = byte(s >> 8) + digest[i*4+3] = byte(s) + } + + return digest +} + +// Sum256 returns the SHA256 checksum of the data. +func Sum256(data []byte) [Size]byte { + var d digest + d.Reset() + d.Write(data) + return d.checkSum() +} + +// Sum224 returns the SHA224 checksum of the data. +func Sum224(data []byte) (sum224 [Size224]byte) { + var d digest + d.is224 = true + d.Reset() + d.Write(data) + sum := d.checkSum() + copy(sum224[:], sum[:Size224]) + return +} + +// ZSL BEGIN + +// HashCompress is an interface implemented by hash functions supporting Compress +type HashCompress interface { + hash.Hash + Compress() []byte +} + +// NewCompress returns a new sha256.HashCompress (which embeds hash.Hash) computing the SHA256 checksum without padding. +func NewCompress() HashCompress { + d := new(digest) + d.Reset() + return d +} + +// Apply SHA-256 to one input block, excluding the padding step specified in [NIST2015, Section 5.1] +func (d *digest) Compress() []byte { + + if d.len != BlockSize { + panic("Compress can only be invoked on 64 bytes of input data") + } + + if d.is224 { + panic("Compress is not available for sha224") + } + + var digest [Size]byte + for i, s := range d.h { + digest[i*4] = byte(s >> 24) + digest[i*4+1] = byte(s >> 16) + digest[i*4+2] = byte(s >> 8) + digest[i*4+3] = byte(s) + } + + return digest[:] +} + +// ZSL END diff --git a/privacy/zsl/zsl/sha256/sha256_test.go b/privacy/zsl/zsl/sha256/sha256_test.go new file mode 100644 index 0000000..279cf5a --- /dev/null +++ b/privacy/zsl/zsl/sha256/sha256_test.go @@ -0,0 +1,189 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// SHA256 hash algorithm. See FIPS 180-2. + +package sha256 + +import ( + "crypto/rand" + "fmt" + "io" + "testing" +) + +type sha256Test struct { + out string + in string +} + +var golden = []sha256Test{ + {"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", ""}, + {"ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb", "a"}, + {"fb8e20fc2e4c3f248c60c39bd652f3c1347298bb977b8b4d5903b85055620603", "ab"}, + {"ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad", "abc"}, + {"88d4266fd4e6338d13b845fcf289579d209c897823b9217da3e161936f031589", "abcd"}, + {"36bbe50ed96841d10443bcb670d6554f0a34b761be67ec9c4a8ad2c0c44ca42c", "abcde"}, + {"bef57ec7f53a6d40beb640a780a639c83bc29ac8a9816f1fc6c5c6dcd93c4721", "abcdef"}, + {"7d1a54127b222502f5b79b5fb0803061152a44f92b37e23c6527baf665d4da9a", "abcdefg"}, + {"9c56cc51b374c3ba189210d5b6d4bf57790d351c96c47c02190ecf1e430635ab", "abcdefgh"}, + {"19cc02f26df43cc571bc9ed7b0c4d29224a3ec229529221725ef76d021c8326f", "abcdefghi"}, + {"72399361da6a7754fec986dca5b7cbaf1c810a28ded4abaf56b2106d06cb78b0", "abcdefghij"}, + {"a144061c271f152da4d151034508fed1c138b8c976339de229c3bb6d4bbb4fce", "Discard medicine more than two years old."}, + {"6dae5caa713a10ad04b46028bf6dad68837c581616a1589a265a11288d4bb5c4", "He who has a shady past knows that nice guys finish last."}, + {"ae7a702a9509039ddbf29f0765e70d0001177914b86459284dab8b348c2dce3f", "I wouldn't marry him with a ten foot pole."}, + {"6748450b01c568586715291dfa3ee018da07d36bb7ea6f180c1af6270215c64f", "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave"}, + {"14b82014ad2b11f661b5ae6a99b75105c2ffac278cd071cd6c05832793635774", "The days of the digital watch are numbered. -Tom Stoppard"}, + {"7102cfd76e2e324889eece5d6c41921b1e142a4ac5a2692be78803097f6a48d8", "Nepal premier won't resign."}, + {"23b1018cd81db1d67983c5f7417c44da9deb582459e378d7a068552ea649dc9f", "For every action there is an equal and opposite government program."}, + {"8001f190dfb527261c4cfcab70c98e8097a7a1922129bc4096950e57c7999a5a", "His money is twice tainted: 'taint yours and 'taint mine."}, + {"8c87deb65505c3993eb24b7a150c4155e82eee6960cf0c3a8114ff736d69cad5", "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977"}, + {"bfb0a67a19cdec3646498b2e0f751bddc41bba4b7f30081b0b932aad214d16d7", "It's a tiny change to the code and not completely disgusting. - Bob Manchek"}, + {"7f9a0b9bf56332e19f5a0ec1ad9c1425a153da1c624868fda44561d6b74daf36", "size: a.out: bad magic"}, + {"b13f81b8aad9e3666879af19886140904f7f429ef083286195982a7588858cfc", "The major problem is with sendmail. -Mark Horton"}, + {"b26c38d61519e894480c70c8374ea35aa0ad05b2ae3d6674eec5f52a69305ed4", "Give me a rock, paper and scissors and I will move the world. CCFestoon"}, + {"049d5e26d4f10222cd841a119e38bd8d2e0d1129728688449575d4ff42b842c1", "If the enemy is within range, then so are you."}, + {"0e116838e3cc1c1a14cd045397e29b4d087aa11b0853fc69ec82e90330d60949", "It's well we cannot hear the screams/That we create in others' dreams."}, + {"4f7d8eb5bcf11de2a56b971021a444aa4eafd6ecd0f307b5109e4e776cd0fe46", "You remind me of a TV show, but that's all right: I watch it anyway."}, + {"61c0cc4c4bd8406d5120b3fb4ebc31ce87667c162f29468b3c779675a85aebce", "C is as portable as Stonehedge!!"}, + {"1fb2eb3688093c4a3f80cd87a5547e2ce940a4f923243a79a2a1e242220693ac", "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley"}, + {"395585ce30617b62c80b93e8208ce866d4edc811a177fdb4b82d3911d8696423", "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction. Lewis-Randall Rule"}, + {"4f9b189a13d030838269dce846b16a1ce9ce81fe63e65de2f636863336a98fe6", "How can you write a big system without C++? -Paul Glick"}, +} + +var golden224 = []sha256Test{ + {"d14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f", ""}, + {"abd37534c7d9a2efb9465de931cd7055ffdb8879563ae98078d6d6d5", "a"}, + {"db3cda86d4429a1d39c148989566b38f7bda0156296bd364ba2f878b", "ab"}, + {"23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7", "abc"}, + {"a76654d8e3550e9a2d67a0eeb6c67b220e5885eddd3fde135806e601", "abcd"}, + {"bdd03d560993e675516ba5a50638b6531ac2ac3d5847c61916cfced6", "abcde"}, + {"7043631cb415556a275a4ebecb802c74ee9f6153908e1792a90b6a98", "abcdef"}, + {"d1884e711701ad81abe0c77a3b0ea12e19ba9af64077286c72fc602d", "abcdefg"}, + {"17eb7d40f0356f8598e89eafad5f6c759b1f822975d9c9b737c8a517", "abcdefgh"}, + {"aeb35915346c584db820d2de7af3929ffafef9222a9bcb26516c7334", "abcdefghi"}, + {"d35e1e5af29ddb0d7e154357df4ad9842afee527c689ee547f753188", "abcdefghij"}, + {"19297f1cef7ddc8a7e947f5c5a341e10f7245045e425db67043988d7", "Discard medicine more than two years old."}, + {"0f10c2eb436251f777fbbd125e260d36aecf180411726c7c885f599a", "He who has a shady past knows that nice guys finish last."}, + {"4d1842104919f314cad8a3cd20b3cba7e8ed3e7abed62b57441358f6", "I wouldn't marry him with a ten foot pole."}, + {"a8ba85c6fe0c48fbffc72bbb2f03fcdbc87ae2dc7a56804d1590fb3b", "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave"}, + {"5543fbab26e67e8885b1a852d567d1cb8b9bfe42e0899584c50449a9", "The days of the digital watch are numbered. -Tom Stoppard"}, + {"65ca107390f5da9efa05d28e57b221657edc7e43a9a18fb15b053ddb", "Nepal premier won't resign."}, + {"84953962be366305a9cc9b5cd16ed019edc37ac96c0deb3e12cca116", "For every action there is an equal and opposite government program."}, + {"35a189ce987151dfd00b3577583cc6a74b9869eecf894459cb52038d", "His money is twice tainted: 'taint yours and 'taint mine."}, + {"2fc333713983edfd4ef2c0da6fb6d6415afb94987c91e4069eb063e6", "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977"}, + {"cbe32d38d577a1b355960a4bc3c659c2dc4670859a19777a875842c4", "It's a tiny change to the code and not completely disgusting. - Bob Manchek"}, + {"a2dc118ce959e027576413a7b440c875cdc8d40df9141d6ef78a57e1", "size: a.out: bad magic"}, + {"d10787e24052bcff26dc484787a54ed819e4e4511c54890ee977bf81", "The major problem is with sendmail. -Mark Horton"}, + {"62efcf16ab8a893acdf2f348aaf06b63039ff1bf55508c830532c9fb", "Give me a rock, paper and scissors and I will move the world. CCFestoon"}, + {"3e9b7e4613c59f58665104c5fa86c272db5d3a2ff30df5bb194a5c99", "If the enemy is within range, then so are you."}, + {"5999c208b8bdf6d471bb7c359ac5b829e73a8211dff686143a4e7f18", "It's well we cannot hear the screams/That we create in others' dreams."}, + {"3b2d67ff54eabc4ef737b14edf87c64280ef582bcdf2a6d56908b405", "You remind me of a TV show, but that's all right: I watch it anyway."}, + {"d0733595d20e4d3d6b5c565a445814d1bbb2fd08b9a3b8ffb97930c6", "C is as portable as Stonehedge!!"}, + {"43fb8aeed8a833175c9295c1165415f98c866ef08a4922959d673507", "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley"}, + {"ec18e66e93afc4fb1604bc2baedbfd20b44c43d76e65c0996d7851c6", "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction. Lewis-Randall Rule"}, + {"86ed2eaa9c75ba98396e5c9fb2f679ecf0ea2ed1e0ee9ceecb4a9332", "How can you write a big system without C++? -Paul Glick"}, +} + +func TestGolden(t *testing.T) { + for i := 0; i < len(golden); i++ { + g := golden[i] + s := fmt.Sprintf("%x", Sum256([]byte(g.in))) + if s != g.out { + t.Fatalf("Sum256 function: sha256(%s) = %s want %s", g.in, s, g.out) + } + c := New() + for j := 0; j < 3; j++ { + if j < 2 { + io.WriteString(c, g.in) + } else { + io.WriteString(c, g.in[0:len(g.in)/2]) + c.Sum(nil) + io.WriteString(c, g.in[len(g.in)/2:]) + } + s := fmt.Sprintf("%x", c.Sum(nil)) + if s != g.out { + t.Fatalf("sha256[%d](%s) = %s want %s", j, g.in, s, g.out) + } + c.Reset() + } + } + for i := 0; i < len(golden224); i++ { + g := golden224[i] + s := fmt.Sprintf("%x", Sum224([]byte(g.in))) + if s != g.out { + t.Fatalf("Sum224 function: sha224(%s) = %s want %s", g.in, s, g.out) + } + c := New224() + for j := 0; j < 3; j++ { + if j < 2 { + io.WriteString(c, g.in) + } else { + io.WriteString(c, g.in[0:len(g.in)/2]) + c.Sum(nil) + io.WriteString(c, g.in[len(g.in)/2:]) + } + s := fmt.Sprintf("%x", c.Sum(nil)) + if s != g.out { + t.Fatalf("sha224[%d](%s) = %s want %s", j, g.in, s, g.out) + } + c.Reset() + } + } +} + +func TestSize(t *testing.T) { + c := New() + if got := c.Size(); got != Size { + t.Errorf("Size = %d; want %d", got, Size) + } + c = New224() + if got := c.Size(); got != Size224 { + t.Errorf("New224.Size = %d; want %d", got, Size224) + } +} + +func TestBlockSize(t *testing.T) { + c := New() + if got := c.BlockSize(); got != BlockSize { + t.Errorf("BlockSize = %d want %d", got, BlockSize) + } +} + +// Tests that blockGeneric (pure Go) and block (in assembly for some architectures) match. +func TestBlockGeneric(t *testing.T) { + gen, asm := New().(*digest), New().(*digest) + buf := make([]byte, BlockSize*20) // arbitrary factor + rand.Read(buf) + blockGeneric(gen, buf) + block(asm, buf) + if *gen != *asm { + t.Error("block and blockGeneric resulted in different states") + } +} + +var bench = New() +var buf = make([]byte, 8192) + +func benchmarkSize(b *testing.B, size int) { + b.SetBytes(int64(size)) + sum := make([]byte, bench.Size()) + for i := 0; i < b.N; i++ { + bench.Reset() + bench.Write(buf[:size]) + bench.Sum(sum[:0]) + } +} + +func BenchmarkHash8Bytes(b *testing.B) { + benchmarkSize(b, 8) +} + +func BenchmarkHash1K(b *testing.B) { + benchmarkSize(b, 1024) +} + +func BenchmarkHash8K(b *testing.B) { + benchmarkSize(b, 8192) +} diff --git a/privacy/zsl/zsl/sha256/sha256block.go b/privacy/zsl/zsl/sha256/sha256block.go new file mode 100644 index 0000000..d43bbf0 --- /dev/null +++ b/privacy/zsl/zsl/sha256/sha256block.go @@ -0,0 +1,126 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// SHA256 block step. +// In its own file so that a faster assembly or C version +// can be substituted easily. + +package sha256 + +var _K = []uint32{ + 0x428a2f98, + 0x71374491, + 0xb5c0fbcf, + 0xe9b5dba5, + 0x3956c25b, + 0x59f111f1, + 0x923f82a4, + 0xab1c5ed5, + 0xd807aa98, + 0x12835b01, + 0x243185be, + 0x550c7dc3, + 0x72be5d74, + 0x80deb1fe, + 0x9bdc06a7, + 0xc19bf174, + 0xe49b69c1, + 0xefbe4786, + 0x0fc19dc6, + 0x240ca1cc, + 0x2de92c6f, + 0x4a7484aa, + 0x5cb0a9dc, + 0x76f988da, + 0x983e5152, + 0xa831c66d, + 0xb00327c8, + 0xbf597fc7, + 0xc6e00bf3, + 0xd5a79147, + 0x06ca6351, + 0x14292967, + 0x27b70a85, + 0x2e1b2138, + 0x4d2c6dfc, + 0x53380d13, + 0x650a7354, + 0x766a0abb, + 0x81c2c92e, + 0x92722c85, + 0xa2bfe8a1, + 0xa81a664b, + 0xc24b8b70, + 0xc76c51a3, + 0xd192e819, + 0xd6990624, + 0xf40e3585, + 0x106aa070, + 0x19a4c116, + 0x1e376c08, + 0x2748774c, + 0x34b0bcb5, + 0x391c0cb3, + 0x4ed8aa4a, + 0x5b9cca4f, + 0x682e6ff3, + 0x748f82ee, + 0x78a5636f, + 0x84c87814, + 0x8cc70208, + 0x90befffa, + 0xa4506ceb, + 0xbef9a3f7, + 0xc67178f2, +} + +func blockGeneric(dig *digest, p []byte) { + var w [64]uint32 + h0, h1, h2, h3, h4, h5, h6, h7 := dig.h[0], dig.h[1], dig.h[2], dig.h[3], dig.h[4], dig.h[5], dig.h[6], dig.h[7] + for len(p) >= chunk { + // Can interlace the computation of w with the + // rounds below if needed for speed. + for i := 0; i < 16; i++ { + j := i * 4 + w[i] = uint32(p[j])<<24 | uint32(p[j+1])<<16 | uint32(p[j+2])<<8 | uint32(p[j+3]) + } + for i := 16; i < 64; i++ { + v1 := w[i-2] + t1 := (v1>>17 | v1<<(32-17)) ^ (v1>>19 | v1<<(32-19)) ^ (v1 >> 10) + v2 := w[i-15] + t2 := (v2>>7 | v2<<(32-7)) ^ (v2>>18 | v2<<(32-18)) ^ (v2 >> 3) + w[i] = t1 + w[i-7] + t2 + w[i-16] + } + + a, b, c, d, e, f, g, h := h0, h1, h2, h3, h4, h5, h6, h7 + + for i := 0; i < 64; i++ { + t1 := h + ((e>>6 | e<<(32-6)) ^ (e>>11 | e<<(32-11)) ^ (e>>25 | e<<(32-25))) + ((e & f) ^ (^e & g)) + _K[i] + w[i] + + t2 := ((a>>2 | a<<(32-2)) ^ (a>>13 | a<<(32-13)) ^ (a>>22 | a<<(32-22))) + ((a & b) ^ (a & c) ^ (b & c)) + + h = g + g = f + f = e + e = d + t1 + d = c + c = b + b = a + a = t1 + t2 + } + + h0 += a + h1 += b + h2 += c + h3 += d + h4 += e + h5 += f + h6 += g + h7 += h + + p = p[chunk:] + } + + dig.h[0], dig.h[1], dig.h[2], dig.h[3], dig.h[4], dig.h[5], dig.h[6], dig.h[7] = h0, h1, h2, h3, h4, h5, h6, h7 +} diff --git a/privacy/zsl/zsl/sha256/sha256block_amd64.s b/privacy/zsl/zsl/sha256/sha256block_amd64.s new file mode 100644 index 0000000..6ab3b52 --- /dev/null +++ b/privacy/zsl/zsl/sha256/sha256block_amd64.s @@ -0,0 +1,1041 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +#include "textflag.h" + +// SHA256 block routine. See sha256block.go for Go equivalent. +// +// The algorithm is detailed in FIPS 180-4: +// +// http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf + +// The avx2-version is described in an Intel White-Paper: +// "Fast SHA-256 Implementations on Intel Architecture Processors" +// To find it, surf to http://www.intel.com/p/en_US/embedded +// and search for that title. +// AVX2 version by Intel, same algorithm as code in Linux kernel: +// https://github.com/torvalds/linux/blob/master/arch/x86/crypto/sha256-avx2-asm.S +// by +// James Guilford +// Kirk Yap +// Tim Chen + +// Wt = Mt; for 0 <= t <= 15 +// Wt = SIGMA1(Wt-2) + SIGMA0(Wt-15) + Wt-16; for 16 <= t <= 63 +// +// a = H0 +// b = H1 +// c = H2 +// d = H3 +// e = H4 +// f = H5 +// g = H6 +// h = H7 +// +// for t = 0 to 63 { +// T1 = h + BIGSIGMA1(e) + Ch(e,f,g) + Kt + Wt +// T2 = BIGSIGMA0(a) + Maj(a,b,c) +// h = g +// g = f +// f = e +// e = d + T1 +// d = c +// c = b +// b = a +// a = T1 + T2 +// } +// +// H0 = a + H0 +// H1 = b + H1 +// H2 = c + H2 +// H3 = d + H3 +// H4 = e + H4 +// H5 = f + H5 +// H6 = g + H6 +// H7 = h + H7 + +// Wt = Mt; for 0 <= t <= 15 +#define MSGSCHEDULE0(index) \ + MOVL (index*4)(SI), AX; \ + BSWAPL AX; \ + MOVL AX, (index*4)(BP) + +// Wt = SIGMA1(Wt-2) + Wt-7 + SIGMA0(Wt-15) + Wt-16; for 16 <= t <= 63 +// SIGMA0(x) = ROTR(7,x) XOR ROTR(18,x) XOR SHR(3,x) +// SIGMA1(x) = ROTR(17,x) XOR ROTR(19,x) XOR SHR(10,x) +#define MSGSCHEDULE1(index) \ + MOVL ((index-2)*4)(BP), AX; \ + MOVL AX, CX; \ + RORL $17, AX; \ + MOVL CX, DX; \ + RORL $19, CX; \ + SHRL $10, DX; \ + MOVL ((index-15)*4)(BP), BX; \ + XORL CX, AX; \ + MOVL BX, CX; \ + XORL DX, AX; \ + RORL $7, BX; \ + MOVL CX, DX; \ + SHRL $3, DX; \ + RORL $18, CX; \ + ADDL ((index-7)*4)(BP), AX; \ + XORL CX, BX; \ + XORL DX, BX; \ + ADDL ((index-16)*4)(BP), BX; \ + ADDL BX, AX; \ + MOVL AX, ((index)*4)(BP) + +// Calculate T1 in AX - uses AX, CX and DX registers. +// h is also used as an accumulator. Wt is passed in AX. +// T1 = h + BIGSIGMA1(e) + Ch(e, f, g) + Kt + Wt +// BIGSIGMA1(x) = ROTR(6,x) XOR ROTR(11,x) XOR ROTR(25,x) +// Ch(x, y, z) = (x AND y) XOR (NOT x AND z) +#define SHA256T1(const, e, f, g, h) \ + ADDL AX, h; \ + MOVL e, AX; \ + ADDL $const, h; \ + MOVL e, CX; \ + RORL $6, AX; \ + MOVL e, DX; \ + RORL $11, CX; \ + XORL CX, AX; \ + MOVL e, CX; \ + RORL $25, DX; \ + ANDL f, CX; \ + XORL AX, DX; \ + MOVL e, AX; \ + NOTL AX; \ + ADDL DX, h; \ + ANDL g, AX; \ + XORL CX, AX; \ + ADDL h, AX + +// Calculate T2 in BX - uses BX, CX, DX and DI registers. +// T2 = BIGSIGMA0(a) + Maj(a, b, c) +// BIGSIGMA0(x) = ROTR(2,x) XOR ROTR(13,x) XOR ROTR(22,x) +// Maj(x, y, z) = (x AND y) XOR (x AND z) XOR (y AND z) +#define SHA256T2(a, b, c) \ + MOVL a, DI; \ + MOVL c, BX; \ + RORL $2, DI; \ + MOVL a, DX; \ + ANDL b, BX; \ + RORL $13, DX; \ + MOVL a, CX; \ + ANDL c, CX; \ + XORL DX, DI; \ + XORL CX, BX; \ + MOVL a, DX; \ + MOVL b, CX; \ + RORL $22, DX; \ + ANDL a, CX; \ + XORL CX, BX; \ + XORL DX, DI; \ + ADDL DI, BX + +// Calculate T1 and T2, then e = d + T1 and a = T1 + T2. +// The values for e and a are stored in d and h, ready for rotation. +#define SHA256ROUND(index, const, a, b, c, d, e, f, g, h) \ + SHA256T1(const, e, f, g, h); \ + SHA256T2(a, b, c); \ + MOVL BX, h; \ + ADDL AX, d; \ + ADDL AX, h + +#define SHA256ROUND0(index, const, a, b, c, d, e, f, g, h) \ + MSGSCHEDULE0(index); \ + SHA256ROUND(index, const, a, b, c, d, e, f, g, h) + +#define SHA256ROUND1(index, const, a, b, c, d, e, f, g, h) \ + MSGSCHEDULE1(index); \ + SHA256ROUND(index, const, a, b, c, d, e, f, g, h) + + +// Definitions for AVX2 version + +// addm (mem), reg +// Add reg to mem using reg-mem add and store +#define addm(P1, P2) \ + ADDL P2, P1; \ + MOVL P1, P2 + +#define XDWORD0 Y4 +#define XDWORD1 Y5 +#define XDWORD2 Y6 +#define XDWORD3 Y7 + +#define XWORD0 X4 +#define XWORD1 X5 +#define XWORD2 X6 +#define XWORD3 X7 + +#define XTMP0 Y0 +#define XTMP1 Y1 +#define XTMP2 Y2 +#define XTMP3 Y3 +#define XTMP4 Y8 +#define XTMP5 Y11 + +#define XFER Y9 + +#define BYTE_FLIP_MASK Y13 // mask to convert LE -> BE +#define X_BYTE_FLIP_MASK X13 + +#define NUM_BYTES DX +#define INP DI + +#define CTX SI // Beginning of digest in memory (a, b, c, ... , h) + +#define a AX +#define b BX +#define c CX +#define d R8 +#define e DX +#define f R9 +#define g R10 +#define h R11 + +#define old_h R11 + +#define TBL BP + +#define SRND SI // SRND is same register as CTX + +#define T1 R12 + +#define y0 R13 +#define y1 R14 +#define y2 R15 +#define y3 DI + +// Offsets +#define XFER_SIZE 2*64*4 +#define INP_END_SIZE 8 +#define INP_SIZE 8 +#define TMP_SIZE 4 + +#define _XFER 0 +#define _INP_END _XFER + XFER_SIZE +#define _INP _INP_END + INP_END_SIZE +#define _TMP _INP + INP_SIZE +#define STACK_SIZE _TMP + TMP_SIZE + +#define ROUND_AND_SCHED_N_0(disp, a, b, c, d, e, f, g, h, XDWORD0, XDWORD1, XDWORD2, XDWORD3) \ + ; \ // ############################# RND N + 0 ############################// + MOVL a, y3; \ // y3 = a // MAJA + RORXL $25, e, y0; \ // y0 = e >> 25 // S1A + RORXL $11, e, y1; \ // y1 = e >> 11 // S1B + ; \ + ADDL (disp + 0*4)(SP)(SRND*1), h; \ // h = k + w + h // disp = k + w + ORL c, y3; \ // y3 = a|c // MAJA + VPALIGNR $4, XDWORD2, XDWORD3, XTMP0; \ // XTMP0 = W[-7] + MOVL f, y2; \ // y2 = f // CH + RORXL $13, a, T1; \ // T1 = a >> 13 // S0B + ; \ + XORL y1, y0; \ // y0 = (e>>25) ^ (e>>11) // S1 + XORL g, y2; \ // y2 = f^g // CH + VPADDD XDWORD0, XTMP0, XTMP0; \ // XTMP0 = W[-7] + W[-16] // y1 = (e >> 6) // S1 + RORXL $6, e, y1; \ // y1 = (e >> 6) // S1 + ; \ + ANDL e, y2; \ // y2 = (f^g)&e // CH + XORL y1, y0; \ // y0 = (e>>25) ^ (e>>11) ^ (e>>6) // S1 + RORXL $22, a, y1; \ // y1 = a >> 22 // S0A + ADDL h, d; \ // d = k + w + h + d // -- + ; \ + ANDL b, y3; \ // y3 = (a|c)&b // MAJA + VPALIGNR $4, XDWORD0, XDWORD1, XTMP1; \ // XTMP1 = W[-15] + XORL T1, y1; \ // y1 = (a>>22) ^ (a>>13) // S0 + RORXL $2, a, T1; \ // T1 = (a >> 2) // S0 + ; \ + XORL g, y2; \ // y2 = CH = ((f^g)&e)^g // CH + VPSRLD $7, XTMP1, XTMP2; \ + XORL T1, y1; \ // y1 = (a>>22) ^ (a>>13) ^ (a>>2) // S0 + MOVL a, T1; \ // T1 = a // MAJB + ANDL c, T1; \ // T1 = a&c // MAJB + ; \ + ADDL y0, y2; \ // y2 = S1 + CH // -- + VPSLLD $(32-7), XTMP1, XTMP3; \ + ORL T1, y3; \ // y3 = MAJ = (a|c)&b)|(a&c) // MAJ + ADDL y1, h; \ // h = k + w + h + S0 // -- + ; \ + ADDL y2, d; \ // d = k + w + h + d + S1 + CH = d + t1 // -- + VPOR XTMP2, XTMP3, XTMP3; \ // XTMP3 = W[-15] ror 7 + ; \ + VPSRLD $18, XTMP1, XTMP2; \ + ADDL y2, h; \ // h = k + w + h + S0 + S1 + CH = t1 + S0// -- + ADDL y3, h // h = t1 + S0 + MAJ // -- + +#define ROUND_AND_SCHED_N_1(disp, a, b, c, d, e, f, g, h, XDWORD0, XDWORD1, XDWORD2, XDWORD3) \ + ; \ // ################################### RND N + 1 ############################ + ; \ + MOVL a, y3; \ // y3 = a // MAJA + RORXL $25, e, y0; \ // y0 = e >> 25 // S1A + RORXL $11, e, y1; \ // y1 = e >> 11 // S1B + ADDL (disp + 1*4)(SP)(SRND*1), h; \ // h = k + w + h // -- + ORL c, y3; \ // y3 = a|c // MAJA + ; \ + VPSRLD $3, XTMP1, XTMP4; \ // XTMP4 = W[-15] >> 3 + MOVL f, y2; \ // y2 = f // CH + RORXL $13, a, T1; \ // T1 = a >> 13 // S0B + XORL y1, y0; \ // y0 = (e>>25) ^ (e>>11) // S1 + XORL g, y2; \ // y2 = f^g // CH + ; \ + RORXL $6, e, y1; \ // y1 = (e >> 6) // S1 + XORL y1, y0; \ // y0 = (e>>25) ^ (e>>11) ^ (e>>6) // S1 + RORXL $22, a, y1; \ // y1 = a >> 22 // S0A + ANDL e, y2; \ // y2 = (f^g)&e // CH + ADDL h, d; \ // d = k + w + h + d // -- + ; \ + VPSLLD $(32-18), XTMP1, XTMP1; \ + ANDL b, y3; \ // y3 = (a|c)&b // MAJA + XORL T1, y1; \ // y1 = (a>>22) ^ (a>>13) // S0 + ; \ + VPXOR XTMP1, XTMP3, XTMP3; \ + RORXL $2, a, T1; \ // T1 = (a >> 2) // S0 + XORL g, y2; \ // y2 = CH = ((f^g)&e)^g // CH + ; \ + VPXOR XTMP2, XTMP3, XTMP3; \ // XTMP3 = W[-15] ror 7 ^ W[-15] ror 18 + XORL T1, y1; \ // y1 = (a>>22) ^ (a>>13) ^ (a>>2) // S0 + MOVL a, T1; \ // T1 = a // MAJB + ANDL c, T1; \ // T1 = a&c // MAJB + ADDL y0, y2; \ // y2 = S1 + CH // -- + ; \ + VPXOR XTMP4, XTMP3, XTMP1; \ // XTMP1 = s0 + VPSHUFD $-6, XDWORD3, XTMP2; \ // XTMP2 = W[-2] {BBAA} + ORL T1, y3; \ // y3 = MAJ = (a|c)&b)|(a&c) // MAJ + ADDL y1, h; \ // h = k + w + h + S0 // -- + ; \ + VPADDD XTMP1, XTMP0, XTMP0; \ // XTMP0 = W[-16] + W[-7] + s0 + ADDL y2, d; \ // d = k + w + h + d + S1 + CH = d + t1 // -- + ADDL y2, h; \ // h = k + w + h + S0 + S1 + CH = t1 + S0// -- + ADDL y3, h; \ // h = t1 + S0 + MAJ // -- + ; \ + VPSRLD $10, XTMP2, XTMP4 // XTMP4 = W[-2] >> 10 {BBAA} + +#define ROUND_AND_SCHED_N_2(disp, a, b, c, d, e, f, g, h, XDWORD0, XDWORD1, XDWORD2, XDWORD3) \ + ; \ // ################################### RND N + 2 ############################ + ; \ + MOVL a, y3; \ // y3 = a // MAJA + RORXL $25, e, y0; \ // y0 = e >> 25 // S1A + ADDL (disp + 2*4)(SP)(SRND*1), h; \ // h = k + w + h // -- + ; \ + VPSRLQ $19, XTMP2, XTMP3; \ // XTMP3 = W[-2] ror 19 {xBxA} + RORXL $11, e, y1; \ // y1 = e >> 11 // S1B + ORL c, y3; \ // y3 = a|c // MAJA + MOVL f, y2; \ // y2 = f // CH + XORL g, y2; \ // y2 = f^g // CH + ; \ + RORXL $13, a, T1; \ // T1 = a >> 13 // S0B + XORL y1, y0; \ // y0 = (e>>25) ^ (e>>11) // S1 + VPSRLQ $17, XTMP2, XTMP2; \ // XTMP2 = W[-2] ror 17 {xBxA} + ANDL e, y2; \ // y2 = (f^g)&e // CH + ; \ + RORXL $6, e, y1; \ // y1 = (e >> 6) // S1 + VPXOR XTMP3, XTMP2, XTMP2; \ + ADDL h, d; \ // d = k + w + h + d // -- + ANDL b, y3; \ // y3 = (a|c)&b // MAJA + ; \ + XORL y1, y0; \ // y0 = (e>>25) ^ (e>>11) ^ (e>>6) // S1 + RORXL $22, a, y1; \ // y1 = a >> 22 // S0A + VPXOR XTMP2, XTMP4, XTMP4; \ // XTMP4 = s1 {xBxA} + XORL g, y2; \ // y2 = CH = ((f^g)&e)^g // CH + ; \ + MOVL f, _TMP(SP); \ + MOVQ $shuff_00BA<>(SB), f; \ // f is used to keep SHUF_00BA + VPSHUFB (f), XTMP4, XTMP4; \ // XTMP4 = s1 {00BA} + MOVL _TMP(SP), f; \ // f is restored + ; \ + XORL T1, y1; \ // y1 = (a>>22) ^ (a>>13) // S0 + RORXL $2, a, T1; \ // T1 = (a >> 2) // S0 + VPADDD XTMP4, XTMP0, XTMP0; \ // XTMP0 = {..., ..., W[1], W[0]} + ; \ + XORL T1, y1; \ // y1 = (a>>22) ^ (a>>13) ^ (a>>2) // S0 + MOVL a, T1; \ // T1 = a // MAJB + ANDL c, T1; \ // T1 = a&c // MAJB + ADDL y0, y2; \ // y2 = S1 + CH // -- + VPSHUFD $80, XTMP0, XTMP2; \ // XTMP2 = W[-2] {DDCC} + ; \ + ORL T1, y3; \ // y3 = MAJ = (a|c)&b)|(a&c) // MAJ + ADDL y1, h; \ // h = k + w + h + S0 // -- + ADDL y2, d; \ // d = k + w + h + d + S1 + CH = d + t1 // -- + ADDL y2, h; \ // h = k + w + h + S0 + S1 + CH = t1 + S0// -- + ; \ + ADDL y3, h // h = t1 + S0 + MAJ // -- + +#define ROUND_AND_SCHED_N_3(disp, a, b, c, d, e, f, g, h, XDWORD0, XDWORD1, XDWORD2, XDWORD3) \ + ; \ // ################################### RND N + 3 ############################ + ; \ + MOVL a, y3; \ // y3 = a // MAJA + RORXL $25, e, y0; \ // y0 = e >> 25 // S1A + RORXL $11, e, y1; \ // y1 = e >> 11 // S1B + ADDL (disp + 3*4)(SP)(SRND*1), h; \ // h = k + w + h // -- + ORL c, y3; \ // y3 = a|c // MAJA + ; \ + VPSRLD $10, XTMP2, XTMP5; \ // XTMP5 = W[-2] >> 10 {DDCC} + MOVL f, y2; \ // y2 = f // CH + RORXL $13, a, T1; \ // T1 = a >> 13 // S0B + XORL y1, y0; \ // y0 = (e>>25) ^ (e>>11) // S1 + XORL g, y2; \ // y2 = f^g // CH + ; \ + VPSRLQ $19, XTMP2, XTMP3; \ // XTMP3 = W[-2] ror 19 {xDxC} + RORXL $6, e, y1; \ // y1 = (e >> 6) // S1 + ANDL e, y2; \ // y2 = (f^g)&e // CH + ADDL h, d; \ // d = k + w + h + d // -- + ANDL b, y3; \ // y3 = (a|c)&b // MAJA + ; \ + VPSRLQ $17, XTMP2, XTMP2; \ // XTMP2 = W[-2] ror 17 {xDxC} + XORL y1, y0; \ // y0 = (e>>25) ^ (e>>11) ^ (e>>6) // S1 + XORL g, y2; \ // y2 = CH = ((f^g)&e)^g // CH + ; \ + VPXOR XTMP3, XTMP2, XTMP2; \ + RORXL $22, a, y1; \ // y1 = a >> 22 // S0A + ADDL y0, y2; \ // y2 = S1 + CH // -- + ; \ + VPXOR XTMP2, XTMP5, XTMP5; \ // XTMP5 = s1 {xDxC} + XORL T1, y1; \ // y1 = (a>>22) ^ (a>>13) // S0 + ADDL y2, d; \ // d = k + w + h + d + S1 + CH = d + t1 // -- + ; \ + RORXL $2, a, T1; \ // T1 = (a >> 2) // S0 + ; \ + MOVL f, _TMP(SP); \ // Save f + MOVQ $shuff_DC00<>(SB), f; \ // SHUF_00DC + VPSHUFB (f), XTMP5, XTMP5; \ // XTMP5 = s1 {DC00} + MOVL _TMP(SP), f; \ // Restore f + ; \ + VPADDD XTMP0, XTMP5, XDWORD0; \ // XDWORD0 = {W[3], W[2], W[1], W[0]} + XORL T1, y1; \ // y1 = (a>>22) ^ (a>>13) ^ (a>>2) // S0 + MOVL a, T1; \ // T1 = a // MAJB + ANDL c, T1; \ // T1 = a&c // MAJB + ORL T1, y3; \ // y3 = MAJ = (a|c)&b)|(a&c) // MAJ + ; \ + ADDL y1, h; \ // h = k + w + h + S0 // -- + ADDL y2, h; \ // h = k + w + h + S0 + S1 + CH = t1 + S0// -- + ADDL y3, h // h = t1 + S0 + MAJ // -- + +#define DO_ROUND_N_0(disp, a, b, c, d, e, f, g, h, old_h) \ + ; \ // ################################### RND N + 0 ########################### + MOVL f, y2; \ // y2 = f // CH + RORXL $25, e, y0; \ // y0 = e >> 25 // S1A + RORXL $11, e, y1; \ // y1 = e >> 11 // S1B + XORL g, y2; \ // y2 = f^g // CH + ; \ + XORL y1, y0; \ // y0 = (e>>25) ^ (e>>11) // S1 + RORXL $6, e, y1; \ // y1 = (e >> 6) // S1 + ANDL e, y2; \ // y2 = (f^g)&e // CH + ; \ + XORL y1, y0; \ // y0 = (e>>25) ^ (e>>11) ^ (e>>6) // S1 + RORXL $13, a, T1; \ // T1 = a >> 13 // S0B + XORL g, y2; \ // y2 = CH = ((f^g)&e)^g // CH + RORXL $22, a, y1; \ // y1 = a >> 22 // S0A + MOVL a, y3; \ // y3 = a // MAJA + ; \ + XORL T1, y1; \ // y1 = (a>>22) ^ (a>>13) // S0 + RORXL $2, a, T1; \ // T1 = (a >> 2) // S0 + ADDL (disp + 0*4)(SP)(SRND*1), h; \ // h = k + w + h // -- + ORL c, y3; \ // y3 = a|c // MAJA + ; \ + XORL T1, y1; \ // y1 = (a>>22) ^ (a>>13) ^ (a>>2) // S0 + MOVL a, T1; \ // T1 = a // MAJB + ANDL b, y3; \ // y3 = (a|c)&b // MAJA + ANDL c, T1; \ // T1 = a&c // MAJB + ADDL y0, y2; \ // y2 = S1 + CH // -- + ; \ + ADDL h, d; \ // d = k + w + h + d // -- + ORL T1, y3; \ // y3 = MAJ = (a|c)&b)|(a&c) // MAJ + ADDL y1, h; \ // h = k + w + h + S0 // -- + ADDL y2, d // d = k + w + h + d + S1 + CH = d + t1 // -- + +#define DO_ROUND_N_1(disp, a, b, c, d, e, f, g, h, old_h) \ + ; \ // ################################### RND N + 1 ########################### + ADDL y2, old_h; \ // h = k + w + h + S0 + S1 + CH = t1 + S0 // -- + MOVL f, y2; \ // y2 = f // CH + RORXL $25, e, y0; \ // y0 = e >> 25 // S1A + RORXL $11, e, y1; \ // y1 = e >> 11 // S1B + XORL g, y2; \ // y2 = f^g // CH + ; \ + XORL y1, y0; \ // y0 = (e>>25) ^ (e>>11) // S1 + RORXL $6, e, y1; \ // y1 = (e >> 6) // S1 + ANDL e, y2; \ // y2 = (f^g)&e // CH + ADDL y3, old_h; \ // h = t1 + S0 + MAJ // -- + ; \ + XORL y1, y0; \ // y0 = (e>>25) ^ (e>>11) ^ (e>>6) // S1 + RORXL $13, a, T1; \ // T1 = a >> 13 // S0B + XORL g, y2; \ // y2 = CH = ((f^g)&e)^g // CH + RORXL $22, a, y1; \ // y1 = a >> 22 // S0A + MOVL a, y3; \ // y3 = a // MAJA + ; \ + XORL T1, y1; \ // y1 = (a>>22) ^ (a>>13) // S0 + RORXL $2, a, T1; \ // T1 = (a >> 2) // S0 + ADDL (disp + 1*4)(SP)(SRND*1), h; \ // h = k + w + h // -- + ORL c, y3; \ // y3 = a|c // MAJA + ; \ + XORL T1, y1; \ // y1 = (a>>22) ^ (a>>13) ^ (a>>2) // S0 + MOVL a, T1; \ // T1 = a // MAJB + ANDL b, y3; \ // y3 = (a|c)&b // MAJA + ANDL c, T1; \ // T1 = a&c // MAJB + ADDL y0, y2; \ // y2 = S1 + CH // -- + ; \ + ADDL h, d; \ // d = k + w + h + d // -- + ORL T1, y3; \ // y3 = MAJ = (a|c)&b)|(a&c) // MAJ + ADDL y1, h; \ // h = k + w + h + S0 // -- + ; \ + ADDL y2, d // d = k + w + h + d + S1 + CH = d + t1 // -- + +#define DO_ROUND_N_2(disp, a, b, c, d, e, f, g, h, old_h) \ + ; \ // ################################### RND N + 2 ############################## + ADDL y2, old_h; \ // h = k + w + h + S0 + S1 + CH = t1 + S0// -- + MOVL f, y2; \ // y2 = f // CH + RORXL $25, e, y0; \ // y0 = e >> 25 // S1A + RORXL $11, e, y1; \ // y1 = e >> 11 // S1B + XORL g, y2; \ // y2 = f^g // CH + ; \ + XORL y1, y0; \ // y0 = (e>>25) ^ (e>>11) // S1 + RORXL $6, e, y1; \ // y1 = (e >> 6) // S1 + ANDL e, y2; \ // y2 = (f^g)&e // CH + ADDL y3, old_h; \ // h = t1 + S0 + MAJ // -- + ; \ + XORL y1, y0; \ // y0 = (e>>25) ^ (e>>11) ^ (e>>6) // S1 + RORXL $13, a, T1; \ // T1 = a >> 13 // S0B + XORL g, y2; \ // y2 = CH = ((f^g)&e)^g // CH + RORXL $22, a, y1; \ // y1 = a >> 22 // S0A + MOVL a, y3; \ // y3 = a // MAJA + ; \ + XORL T1, y1; \ // y1 = (a>>22) ^ (a>>13) // S0 + RORXL $2, a, T1; \ // T1 = (a >> 2) // S0 + ADDL (disp + 2*4)(SP)(SRND*1), h; \ // h = k + w + h // -- + ORL c, y3; \ // y3 = a|c // MAJA + ; \ + XORL T1, y1; \ // y1 = (a>>22) ^ (a>>13) ^ (a>>2) // S0 + MOVL a, T1; \ // T1 = a // MAJB + ANDL b, y3; \ // y3 = (a|c)&b // MAJA + ANDL c, T1; \ // T1 = a&c // MAJB + ADDL y0, y2; \ // y2 = S1 + CH // -- + ; \ + ADDL h, d; \ // d = k + w + h + d // -- + ORL T1, y3; \ // y3 = MAJ = (a|c)&b)|(a&c) // MAJ + ADDL y1, h; \ // h = k + w + h + S0 // -- + ; \ + ADDL y2, d // d = k + w + h + d + S1 + CH = d + t1 // -- + +#define DO_ROUND_N_3(disp, a, b, c, d, e, f, g, h, old_h) \ + ; \ // ################################### RND N + 3 ########################### + ADDL y2, old_h; \ // h = k + w + h + S0 + S1 + CH = t1 + S0// -- + MOVL f, y2; \ // y2 = f // CH + RORXL $25, e, y0; \ // y0 = e >> 25 // S1A + RORXL $11, e, y1; \ // y1 = e >> 11 // S1B + XORL g, y2; \ // y2 = f^g // CH + ; \ + XORL y1, y0; \ // y0 = (e>>25) ^ (e>>11) // S1 + RORXL $6, e, y1; \ // y1 = (e >> 6) // S1 + ANDL e, y2; \ // y2 = (f^g)&e // CH + ADDL y3, old_h; \ // h = t1 + S0 + MAJ // -- + ; \ + XORL y1, y0; \ // y0 = (e>>25) ^ (e>>11) ^ (e>>6) // S1 + RORXL $13, a, T1; \ // T1 = a >> 13 // S0B + XORL g, y2; \ // y2 = CH = ((f^g)&e)^g // CH + RORXL $22, a, y1; \ // y1 = a >> 22 // S0A + MOVL a, y3; \ // y3 = a // MAJA + ; \ + XORL T1, y1; \ // y1 = (a>>22) ^ (a>>13) // S0 + RORXL $2, a, T1; \ // T1 = (a >> 2) // S0 + ADDL (disp + 3*4)(SP)(SRND*1), h; \ // h = k + w + h // -- + ORL c, y3; \ // y3 = a|c // MAJA + ; \ + XORL T1, y1; \ // y1 = (a>>22) ^ (a>>13) ^ (a>>2) // S0 + MOVL a, T1; \ // T1 = a // MAJB + ANDL b, y3; \ // y3 = (a|c)&b // MAJA + ANDL c, T1; \ // T1 = a&c // MAJB + ADDL y0, y2; \ // y2 = S1 + CH // -- + ; \ + ADDL h, d; \ // d = k + w + h + d // -- + ORL T1, y3; \ // y3 = MAJ = (a|c)&b)|(a&c) // MAJ + ADDL y1, h; \ // h = k + w + h + S0 // -- + ; \ + ADDL y2, d; \ // d = k + w + h + d + S1 + CH = d + t1 // -- + ; \ + ADDL y2, h; \ // h = k + w + h + S0 + S1 + CH = t1 + S0// -- + ; \ + ADDL y3, h // h = t1 + S0 + MAJ // -- + +TEXT ·block(SB), 0, $536-32 + CMPB runtime·support_avx2(SB), $1 + JE avx2 + + MOVQ p_base+8(FP), SI + MOVQ p_len+16(FP), DX + SHRQ $6, DX + SHLQ $6, DX + + LEAQ (SI)(DX*1), DI + MOVQ DI, 256(SP) + CMPQ SI, DI + JEQ end + + MOVQ dig+0(FP), BP + MOVL (0*4)(BP), R8 // a = H0 + MOVL (1*4)(BP), R9 // b = H1 + MOVL (2*4)(BP), R10 // c = H2 + MOVL (3*4)(BP), R11 // d = H3 + MOVL (4*4)(BP), R12 // e = H4 + MOVL (5*4)(BP), R13 // f = H5 + MOVL (6*4)(BP), R14 // g = H6 + MOVL (7*4)(BP), R15 // h = H7 + +loop: + MOVQ SP, BP + + SHA256ROUND0(0, 0x428a2f98, R8, R9, R10, R11, R12, R13, R14, R15) + SHA256ROUND0(1, 0x71374491, R15, R8, R9, R10, R11, R12, R13, R14) + SHA256ROUND0(2, 0xb5c0fbcf, R14, R15, R8, R9, R10, R11, R12, R13) + SHA256ROUND0(3, 0xe9b5dba5, R13, R14, R15, R8, R9, R10, R11, R12) + SHA256ROUND0(4, 0x3956c25b, R12, R13, R14, R15, R8, R9, R10, R11) + SHA256ROUND0(5, 0x59f111f1, R11, R12, R13, R14, R15, R8, R9, R10) + SHA256ROUND0(6, 0x923f82a4, R10, R11, R12, R13, R14, R15, R8, R9) + SHA256ROUND0(7, 0xab1c5ed5, R9, R10, R11, R12, R13, R14, R15, R8) + SHA256ROUND0(8, 0xd807aa98, R8, R9, R10, R11, R12, R13, R14, R15) + SHA256ROUND0(9, 0x12835b01, R15, R8, R9, R10, R11, R12, R13, R14) + SHA256ROUND0(10, 0x243185be, R14, R15, R8, R9, R10, R11, R12, R13) + SHA256ROUND0(11, 0x550c7dc3, R13, R14, R15, R8, R9, R10, R11, R12) + SHA256ROUND0(12, 0x72be5d74, R12, R13, R14, R15, R8, R9, R10, R11) + SHA256ROUND0(13, 0x80deb1fe, R11, R12, R13, R14, R15, R8, R9, R10) + SHA256ROUND0(14, 0x9bdc06a7, R10, R11, R12, R13, R14, R15, R8, R9) + SHA256ROUND0(15, 0xc19bf174, R9, R10, R11, R12, R13, R14, R15, R8) + + SHA256ROUND1(16, 0xe49b69c1, R8, R9, R10, R11, R12, R13, R14, R15) + SHA256ROUND1(17, 0xefbe4786, R15, R8, R9, R10, R11, R12, R13, R14) + SHA256ROUND1(18, 0x0fc19dc6, R14, R15, R8, R9, R10, R11, R12, R13) + SHA256ROUND1(19, 0x240ca1cc, R13, R14, R15, R8, R9, R10, R11, R12) + SHA256ROUND1(20, 0x2de92c6f, R12, R13, R14, R15, R8, R9, R10, R11) + SHA256ROUND1(21, 0x4a7484aa, R11, R12, R13, R14, R15, R8, R9, R10) + SHA256ROUND1(22, 0x5cb0a9dc, R10, R11, R12, R13, R14, R15, R8, R9) + SHA256ROUND1(23, 0x76f988da, R9, R10, R11, R12, R13, R14, R15, R8) + SHA256ROUND1(24, 0x983e5152, R8, R9, R10, R11, R12, R13, R14, R15) + SHA256ROUND1(25, 0xa831c66d, R15, R8, R9, R10, R11, R12, R13, R14) + SHA256ROUND1(26, 0xb00327c8, R14, R15, R8, R9, R10, R11, R12, R13) + SHA256ROUND1(27, 0xbf597fc7, R13, R14, R15, R8, R9, R10, R11, R12) + SHA256ROUND1(28, 0xc6e00bf3, R12, R13, R14, R15, R8, R9, R10, R11) + SHA256ROUND1(29, 0xd5a79147, R11, R12, R13, R14, R15, R8, R9, R10) + SHA256ROUND1(30, 0x06ca6351, R10, R11, R12, R13, R14, R15, R8, R9) + SHA256ROUND1(31, 0x14292967, R9, R10, R11, R12, R13, R14, R15, R8) + SHA256ROUND1(32, 0x27b70a85, R8, R9, R10, R11, R12, R13, R14, R15) + SHA256ROUND1(33, 0x2e1b2138, R15, R8, R9, R10, R11, R12, R13, R14) + SHA256ROUND1(34, 0x4d2c6dfc, R14, R15, R8, R9, R10, R11, R12, R13) + SHA256ROUND1(35, 0x53380d13, R13, R14, R15, R8, R9, R10, R11, R12) + SHA256ROUND1(36, 0x650a7354, R12, R13, R14, R15, R8, R9, R10, R11) + SHA256ROUND1(37, 0x766a0abb, R11, R12, R13, R14, R15, R8, R9, R10) + SHA256ROUND1(38, 0x81c2c92e, R10, R11, R12, R13, R14, R15, R8, R9) + SHA256ROUND1(39, 0x92722c85, R9, R10, R11, R12, R13, R14, R15, R8) + SHA256ROUND1(40, 0xa2bfe8a1, R8, R9, R10, R11, R12, R13, R14, R15) + SHA256ROUND1(41, 0xa81a664b, R15, R8, R9, R10, R11, R12, R13, R14) + SHA256ROUND1(42, 0xc24b8b70, R14, R15, R8, R9, R10, R11, R12, R13) + SHA256ROUND1(43, 0xc76c51a3, R13, R14, R15, R8, R9, R10, R11, R12) + SHA256ROUND1(44, 0xd192e819, R12, R13, R14, R15, R8, R9, R10, R11) + SHA256ROUND1(45, 0xd6990624, R11, R12, R13, R14, R15, R8, R9, R10) + SHA256ROUND1(46, 0xf40e3585, R10, R11, R12, R13, R14, R15, R8, R9) + SHA256ROUND1(47, 0x106aa070, R9, R10, R11, R12, R13, R14, R15, R8) + SHA256ROUND1(48, 0x19a4c116, R8, R9, R10, R11, R12, R13, R14, R15) + SHA256ROUND1(49, 0x1e376c08, R15, R8, R9, R10, R11, R12, R13, R14) + SHA256ROUND1(50, 0x2748774c, R14, R15, R8, R9, R10, R11, R12, R13) + SHA256ROUND1(51, 0x34b0bcb5, R13, R14, R15, R8, R9, R10, R11, R12) + SHA256ROUND1(52, 0x391c0cb3, R12, R13, R14, R15, R8, R9, R10, R11) + SHA256ROUND1(53, 0x4ed8aa4a, R11, R12, R13, R14, R15, R8, R9, R10) + SHA256ROUND1(54, 0x5b9cca4f, R10, R11, R12, R13, R14, R15, R8, R9) + SHA256ROUND1(55, 0x682e6ff3, R9, R10, R11, R12, R13, R14, R15, R8) + SHA256ROUND1(56, 0x748f82ee, R8, R9, R10, R11, R12, R13, R14, R15) + SHA256ROUND1(57, 0x78a5636f, R15, R8, R9, R10, R11, R12, R13, R14) + SHA256ROUND1(58, 0x84c87814, R14, R15, R8, R9, R10, R11, R12, R13) + SHA256ROUND1(59, 0x8cc70208, R13, R14, R15, R8, R9, R10, R11, R12) + SHA256ROUND1(60, 0x90befffa, R12, R13, R14, R15, R8, R9, R10, R11) + SHA256ROUND1(61, 0xa4506ceb, R11, R12, R13, R14, R15, R8, R9, R10) + SHA256ROUND1(62, 0xbef9a3f7, R10, R11, R12, R13, R14, R15, R8, R9) + SHA256ROUND1(63, 0xc67178f2, R9, R10, R11, R12, R13, R14, R15, R8) + + MOVQ dig+0(FP), BP + ADDL (0*4)(BP), R8 // H0 = a + H0 + MOVL R8, (0*4)(BP) + ADDL (1*4)(BP), R9 // H1 = b + H1 + MOVL R9, (1*4)(BP) + ADDL (2*4)(BP), R10 // H2 = c + H2 + MOVL R10, (2*4)(BP) + ADDL (3*4)(BP), R11 // H3 = d + H3 + MOVL R11, (3*4)(BP) + ADDL (4*4)(BP), R12 // H4 = e + H4 + MOVL R12, (4*4)(BP) + ADDL (5*4)(BP), R13 // H5 = f + H5 + MOVL R13, (5*4)(BP) + ADDL (6*4)(BP), R14 // H6 = g + H6 + MOVL R14, (6*4)(BP) + ADDL (7*4)(BP), R15 // H7 = h + H7 + MOVL R15, (7*4)(BP) + + ADDQ $64, SI + CMPQ SI, 256(SP) + JB loop + +end: + RET + +avx2: + MOVQ dig+0(FP), CTX // d.h[8] + MOVQ p_base+8(FP), INP + MOVQ p_len+16(FP), NUM_BYTES + + LEAQ -64(INP)(NUM_BYTES*1), NUM_BYTES // Pointer to the last block + MOVQ NUM_BYTES, _INP_END(SP) + + CMPQ NUM_BYTES, INP + JE avx2_only_one_block + + // Load initial digest + MOVL 0(CTX), a // a = H0 + MOVL 4(CTX), b // b = H1 + MOVL 8(CTX), c // c = H2 + MOVL 12(CTX), d // d = H3 + MOVL 16(CTX), e // e = H4 + MOVL 20(CTX), f // f = H5 + MOVL 24(CTX), g // g = H6 + MOVL 28(CTX), h // h = H7 + +avx2_loop0: // at each iteration works with one block (512 bit) + + VMOVDQU (0*32)(INP), XTMP0 + VMOVDQU (1*32)(INP), XTMP1 + VMOVDQU (2*32)(INP), XTMP2 + VMOVDQU (3*32)(INP), XTMP3 + + MOVQ $flip_mask<>(SB), BP // BYTE_FLIP_MASK + VMOVDQU (BP), BYTE_FLIP_MASK + + // Apply Byte Flip Mask: LE -> BE + VPSHUFB BYTE_FLIP_MASK, XTMP0, XTMP0 + VPSHUFB BYTE_FLIP_MASK, XTMP1, XTMP1 + VPSHUFB BYTE_FLIP_MASK, XTMP2, XTMP2 + VPSHUFB BYTE_FLIP_MASK, XTMP3, XTMP3 + + // Transpose data into high/low parts + VPERM2I128 $0x20, XTMP2, XTMP0, XDWORD0 // w3, w2, w1, w0 + VPERM2I128 $0x31, XTMP2, XTMP0, XDWORD1 // w7, w6, w5, w4 + VPERM2I128 $0x20, XTMP3, XTMP1, XDWORD2 // w11, w10, w9, w8 + VPERM2I128 $0x31, XTMP3, XTMP1, XDWORD3 // w15, w14, w13, w12 + + MOVQ $K256<>(SB), TBL // Loading address of table with round-specific constants + +avx2_last_block_enter: + ADDQ $64, INP + MOVQ INP, _INP(SP) + XORQ SRND, SRND + +avx2_loop1: // for w0 - w47 + // Do 4 rounds and scheduling + VPADDD 0*32(TBL)(SRND*1), XDWORD0, XFER + VMOVDQU XFER, (_XFER + 0*32)(SP)(SRND*1) + ROUND_AND_SCHED_N_0(_XFER + 0*32, a, b, c, d, e, f, g, h, XDWORD0, XDWORD1, XDWORD2, XDWORD3) + ROUND_AND_SCHED_N_1(_XFER + 0*32, h, a, b, c, d, e, f, g, XDWORD0, XDWORD1, XDWORD2, XDWORD3) + ROUND_AND_SCHED_N_2(_XFER + 0*32, g, h, a, b, c, d, e, f, XDWORD0, XDWORD1, XDWORD2, XDWORD3) + ROUND_AND_SCHED_N_3(_XFER + 0*32, f, g, h, a, b, c, d, e, XDWORD0, XDWORD1, XDWORD2, XDWORD3) + + // Do 4 rounds and scheduling + VPADDD 1*32(TBL)(SRND*1), XDWORD1, XFER + VMOVDQU XFER, (_XFER + 1*32)(SP)(SRND*1) + ROUND_AND_SCHED_N_0(_XFER + 1*32, e, f, g, h, a, b, c, d, XDWORD1, XDWORD2, XDWORD3, XDWORD0) + ROUND_AND_SCHED_N_1(_XFER + 1*32, d, e, f, g, h, a, b, c, XDWORD1, XDWORD2, XDWORD3, XDWORD0) + ROUND_AND_SCHED_N_2(_XFER + 1*32, c, d, e, f, g, h, a, b, XDWORD1, XDWORD2, XDWORD3, XDWORD0) + ROUND_AND_SCHED_N_3(_XFER + 1*32, b, c, d, e, f, g, h, a, XDWORD1, XDWORD2, XDWORD3, XDWORD0) + + // Do 4 rounds and scheduling + VPADDD 2*32(TBL)(SRND*1), XDWORD2, XFER + VMOVDQU XFER, (_XFER + 2*32)(SP)(SRND*1) + ROUND_AND_SCHED_N_0(_XFER + 2*32, a, b, c, d, e, f, g, h, XDWORD2, XDWORD3, XDWORD0, XDWORD1) + ROUND_AND_SCHED_N_1(_XFER + 2*32, h, a, b, c, d, e, f, g, XDWORD2, XDWORD3, XDWORD0, XDWORD1) + ROUND_AND_SCHED_N_2(_XFER + 2*32, g, h, a, b, c, d, e, f, XDWORD2, XDWORD3, XDWORD0, XDWORD1) + ROUND_AND_SCHED_N_3(_XFER + 2*32, f, g, h, a, b, c, d, e, XDWORD2, XDWORD3, XDWORD0, XDWORD1) + + // Do 4 rounds and scheduling + VPADDD 3*32(TBL)(SRND*1), XDWORD3, XFER + VMOVDQU XFER, (_XFER + 3*32)(SP)(SRND*1) + ROUND_AND_SCHED_N_0(_XFER + 3*32, e, f, g, h, a, b, c, d, XDWORD3, XDWORD0, XDWORD1, XDWORD2) + ROUND_AND_SCHED_N_1(_XFER + 3*32, d, e, f, g, h, a, b, c, XDWORD3, XDWORD0, XDWORD1, XDWORD2) + ROUND_AND_SCHED_N_2(_XFER + 3*32, c, d, e, f, g, h, a, b, XDWORD3, XDWORD0, XDWORD1, XDWORD2) + ROUND_AND_SCHED_N_3(_XFER + 3*32, b, c, d, e, f, g, h, a, XDWORD3, XDWORD0, XDWORD1, XDWORD2) + + ADDQ $4*32, SRND + CMPQ SRND, $3*4*32 + JB avx2_loop1 + +avx2_loop2: + // w48 - w63 processed with no scheduliung (last 16 rounds) + VPADDD 0*32(TBL)(SRND*1), XDWORD0, XFER + VMOVDQU XFER, (_XFER + 0*32)(SP)(SRND*1) + DO_ROUND_N_0(_XFER + 0*32, a, b, c, d, e, f, g, h, h) + DO_ROUND_N_1(_XFER + 0*32, h, a, b, c, d, e, f, g, h) + DO_ROUND_N_2(_XFER + 0*32, g, h, a, b, c, d, e, f, g) + DO_ROUND_N_3(_XFER + 0*32, f, g, h, a, b, c, d, e, f) + + VPADDD 1*32(TBL)(SRND*1), XDWORD1, XFER + VMOVDQU XFER, (_XFER + 1*32)(SP)(SRND*1) + DO_ROUND_N_0(_XFER + 1*32, e, f, g, h, a, b, c, d, e) + DO_ROUND_N_1(_XFER + 1*32, d, e, f, g, h, a, b, c, d) + DO_ROUND_N_2(_XFER + 1*32, c, d, e, f, g, h, a, b, c) + DO_ROUND_N_3(_XFER + 1*32, b, c, d, e, f, g, h, a, b) + + ADDQ $2*32, SRND + + VMOVDQU XDWORD2, XDWORD0 + VMOVDQU XDWORD3, XDWORD1 + + CMPQ SRND, $4*4*32 + JB avx2_loop2 + + MOVQ dig+0(FP), CTX // d.h[8] + MOVQ _INP(SP), INP + + addm( 0(CTX), a) + addm( 4(CTX), b) + addm( 8(CTX), c) + addm( 12(CTX), d) + addm( 16(CTX), e) + addm( 20(CTX), f) + addm( 24(CTX), g) + addm( 28(CTX), h) + + CMPQ _INP_END(SP), INP + JB done_hash + + XORQ SRND, SRND + +avx2_loop3: // Do second block using previously scheduled results + DO_ROUND_N_0(_XFER + 0*32 + 16, a, b, c, d, e, f, g, h, a) + DO_ROUND_N_1(_XFER + 0*32 + 16, h, a, b, c, d, e, f, g, h) + DO_ROUND_N_2(_XFER + 0*32 + 16, g, h, a, b, c, d, e, f, g) + DO_ROUND_N_3(_XFER + 0*32 + 16, f, g, h, a, b, c, d, e, f) + + DO_ROUND_N_0(_XFER + 1*32 + 16, e, f, g, h, a, b, c, d, e) + DO_ROUND_N_1(_XFER + 1*32 + 16, d, e, f, g, h, a, b, c, d) + DO_ROUND_N_2(_XFER + 1*32 + 16, c, d, e, f, g, h, a, b, c) + DO_ROUND_N_3(_XFER + 1*32 + 16, b, c, d, e, f, g, h, a, b) + + ADDQ $2*32, SRND + CMPQ SRND, $4*4*32 + JB avx2_loop3 + + MOVQ dig+0(FP), CTX // d.h[8] + MOVQ _INP(SP), INP + ADDQ $64, INP + + addm( 0(CTX), a) + addm( 4(CTX), b) + addm( 8(CTX), c) + addm( 12(CTX), d) + addm( 16(CTX), e) + addm( 20(CTX), f) + addm( 24(CTX), g) + addm( 28(CTX), h) + + CMPQ _INP_END(SP), INP + JA avx2_loop0 + JB done_hash + +avx2_do_last_block: + + VMOVDQU 0(INP), XWORD0 + VMOVDQU 16(INP), XWORD1 + VMOVDQU 32(INP), XWORD2 + VMOVDQU 48(INP), XWORD3 + + MOVQ $flip_mask<>(SB), BP + VMOVDQU (BP), X_BYTE_FLIP_MASK + + VPSHUFB X_BYTE_FLIP_MASK, XWORD0, XWORD0 + VPSHUFB X_BYTE_FLIP_MASK, XWORD1, XWORD1 + VPSHUFB X_BYTE_FLIP_MASK, XWORD2, XWORD2 + VPSHUFB X_BYTE_FLIP_MASK, XWORD3, XWORD3 + + MOVQ $K256<>(SB), TBL + + JMP avx2_last_block_enter + +avx2_only_one_block: + // Load initial digest + MOVL 0(CTX), a // a = H0 + MOVL 4(CTX), b // b = H1 + MOVL 8(CTX), c // c = H2 + MOVL 12(CTX), d // d = H3 + MOVL 16(CTX), e // e = H4 + MOVL 20(CTX), f // f = H5 + MOVL 24(CTX), g // g = H6 + MOVL 28(CTX), h // h = H7 + + JMP avx2_do_last_block + +done_hash: + VZEROUPPER + RET + +// shuffle byte order from LE to BE +DATA flip_mask<>+0x00(SB)/8, $0x0405060700010203 +DATA flip_mask<>+0x08(SB)/8, $0x0c0d0e0f08090a0b +DATA flip_mask<>+0x10(SB)/8, $0x0405060700010203 +DATA flip_mask<>+0x18(SB)/8, $0x0c0d0e0f08090a0b +GLOBL flip_mask<>(SB), 8, $32 + +// shuffle xBxA -> 00BA +DATA shuff_00BA<>+0x00(SB)/8, $0x0b0a090803020100 +DATA shuff_00BA<>+0x08(SB)/8, $0xFFFFFFFFFFFFFFFF +DATA shuff_00BA<>+0x10(SB)/8, $0x0b0a090803020100 +DATA shuff_00BA<>+0x18(SB)/8, $0xFFFFFFFFFFFFFFFF +GLOBL shuff_00BA<>(SB), 8, $32 + +// shuffle xDxC -> DC00 +DATA shuff_DC00<>+0x00(SB)/8, $0xFFFFFFFFFFFFFFFF +DATA shuff_DC00<>+0x08(SB)/8, $0x0b0a090803020100 +DATA shuff_DC00<>+0x10(SB)/8, $0xFFFFFFFFFFFFFFFF +DATA shuff_DC00<>+0x18(SB)/8, $0x0b0a090803020100 +GLOBL shuff_DC00<>(SB), 8, $32 + +// Round specific constants +DATA K256<>+0x00(SB)/4, $0x428a2f98 // k1 +DATA K256<>+0x04(SB)/4, $0x71374491 // k2 +DATA K256<>+0x08(SB)/4, $0xb5c0fbcf // k3 +DATA K256<>+0x0c(SB)/4, $0xe9b5dba5 // k4 +DATA K256<>+0x10(SB)/4, $0x428a2f98 // k1 +DATA K256<>+0x14(SB)/4, $0x71374491 // k2 +DATA K256<>+0x18(SB)/4, $0xb5c0fbcf // k3 +DATA K256<>+0x1c(SB)/4, $0xe9b5dba5 // k4 + +DATA K256<>+0x20(SB)/4, $0x3956c25b // k5 - k8 +DATA K256<>+0x24(SB)/4, $0x59f111f1 +DATA K256<>+0x28(SB)/4, $0x923f82a4 +DATA K256<>+0x2c(SB)/4, $0xab1c5ed5 +DATA K256<>+0x30(SB)/4, $0x3956c25b +DATA K256<>+0x34(SB)/4, $0x59f111f1 +DATA K256<>+0x38(SB)/4, $0x923f82a4 +DATA K256<>+0x3c(SB)/4, $0xab1c5ed5 + +DATA K256<>+0x40(SB)/4, $0xd807aa98 // k9 - k12 +DATA K256<>+0x44(SB)/4, $0x12835b01 +DATA K256<>+0x48(SB)/4, $0x243185be +DATA K256<>+0x4c(SB)/4, $0x550c7dc3 +DATA K256<>+0x50(SB)/4, $0xd807aa98 +DATA K256<>+0x54(SB)/4, $0x12835b01 +DATA K256<>+0x58(SB)/4, $0x243185be +DATA K256<>+0x5c(SB)/4, $0x550c7dc3 + +DATA K256<>+0x60(SB)/4, $0x72be5d74 // k13 - k16 +DATA K256<>+0x64(SB)/4, $0x80deb1fe +DATA K256<>+0x68(SB)/4, $0x9bdc06a7 +DATA K256<>+0x6c(SB)/4, $0xc19bf174 +DATA K256<>+0x70(SB)/4, $0x72be5d74 +DATA K256<>+0x74(SB)/4, $0x80deb1fe +DATA K256<>+0x78(SB)/4, $0x9bdc06a7 +DATA K256<>+0x7c(SB)/4, $0xc19bf174 + +DATA K256<>+0x80(SB)/4, $0xe49b69c1 // k17 - k20 +DATA K256<>+0x84(SB)/4, $0xefbe4786 +DATA K256<>+0x88(SB)/4, $0x0fc19dc6 +DATA K256<>+0x8c(SB)/4, $0x240ca1cc +DATA K256<>+0x90(SB)/4, $0xe49b69c1 +DATA K256<>+0x94(SB)/4, $0xefbe4786 +DATA K256<>+0x98(SB)/4, $0x0fc19dc6 +DATA K256<>+0x9c(SB)/4, $0x240ca1cc + +DATA K256<>+0xa0(SB)/4, $0x2de92c6f // k21 - k24 +DATA K256<>+0xa4(SB)/4, $0x4a7484aa +DATA K256<>+0xa8(SB)/4, $0x5cb0a9dc +DATA K256<>+0xac(SB)/4, $0x76f988da +DATA K256<>+0xb0(SB)/4, $0x2de92c6f +DATA K256<>+0xb4(SB)/4, $0x4a7484aa +DATA K256<>+0xb8(SB)/4, $0x5cb0a9dc +DATA K256<>+0xbc(SB)/4, $0x76f988da + +DATA K256<>+0xc0(SB)/4, $0x983e5152 // k25 - k28 +DATA K256<>+0xc4(SB)/4, $0xa831c66d +DATA K256<>+0xc8(SB)/4, $0xb00327c8 +DATA K256<>+0xcc(SB)/4, $0xbf597fc7 +DATA K256<>+0xd0(SB)/4, $0x983e5152 +DATA K256<>+0xd4(SB)/4, $0xa831c66d +DATA K256<>+0xd8(SB)/4, $0xb00327c8 +DATA K256<>+0xdc(SB)/4, $0xbf597fc7 + +DATA K256<>+0xe0(SB)/4, $0xc6e00bf3 // k29 - k32 +DATA K256<>+0xe4(SB)/4, $0xd5a79147 +DATA K256<>+0xe8(SB)/4, $0x06ca6351 +DATA K256<>+0xec(SB)/4, $0x14292967 +DATA K256<>+0xf0(SB)/4, $0xc6e00bf3 +DATA K256<>+0xf4(SB)/4, $0xd5a79147 +DATA K256<>+0xf8(SB)/4, $0x06ca6351 +DATA K256<>+0xfc(SB)/4, $0x14292967 + +DATA K256<>+0x100(SB)/4, $0x27b70a85 +DATA K256<>+0x104(SB)/4, $0x2e1b2138 +DATA K256<>+0x108(SB)/4, $0x4d2c6dfc +DATA K256<>+0x10c(SB)/4, $0x53380d13 +DATA K256<>+0x110(SB)/4, $0x27b70a85 +DATA K256<>+0x114(SB)/4, $0x2e1b2138 +DATA K256<>+0x118(SB)/4, $0x4d2c6dfc +DATA K256<>+0x11c(SB)/4, $0x53380d13 + +DATA K256<>+0x120(SB)/4, $0x650a7354 +DATA K256<>+0x124(SB)/4, $0x766a0abb +DATA K256<>+0x128(SB)/4, $0x81c2c92e +DATA K256<>+0x12c(SB)/4, $0x92722c85 +DATA K256<>+0x130(SB)/4, $0x650a7354 +DATA K256<>+0x134(SB)/4, $0x766a0abb +DATA K256<>+0x138(SB)/4, $0x81c2c92e +DATA K256<>+0x13c(SB)/4, $0x92722c85 + +DATA K256<>+0x140(SB)/4, $0xa2bfe8a1 +DATA K256<>+0x144(SB)/4, $0xa81a664b +DATA K256<>+0x148(SB)/4, $0xc24b8b70 +DATA K256<>+0x14c(SB)/4, $0xc76c51a3 +DATA K256<>+0x150(SB)/4, $0xa2bfe8a1 +DATA K256<>+0x154(SB)/4, $0xa81a664b +DATA K256<>+0x158(SB)/4, $0xc24b8b70 +DATA K256<>+0x15c(SB)/4, $0xc76c51a3 + +DATA K256<>+0x160(SB)/4, $0xd192e819 +DATA K256<>+0x164(SB)/4, $0xd6990624 +DATA K256<>+0x168(SB)/4, $0xf40e3585 +DATA K256<>+0x16c(SB)/4, $0x106aa070 +DATA K256<>+0x170(SB)/4, $0xd192e819 +DATA K256<>+0x174(SB)/4, $0xd6990624 +DATA K256<>+0x178(SB)/4, $0xf40e3585 +DATA K256<>+0x17c(SB)/4, $0x106aa070 + +DATA K256<>+0x180(SB)/4, $0x19a4c116 +DATA K256<>+0x184(SB)/4, $0x1e376c08 +DATA K256<>+0x188(SB)/4, $0x2748774c +DATA K256<>+0x18c(SB)/4, $0x34b0bcb5 +DATA K256<>+0x190(SB)/4, $0x19a4c116 +DATA K256<>+0x194(SB)/4, $0x1e376c08 +DATA K256<>+0x198(SB)/4, $0x2748774c +DATA K256<>+0x19c(SB)/4, $0x34b0bcb5 + +DATA K256<>+0x1a0(SB)/4, $0x391c0cb3 +DATA K256<>+0x1a4(SB)/4, $0x4ed8aa4a +DATA K256<>+0x1a8(SB)/4, $0x5b9cca4f +DATA K256<>+0x1ac(SB)/4, $0x682e6ff3 +DATA K256<>+0x1b0(SB)/4, $0x391c0cb3 +DATA K256<>+0x1b4(SB)/4, $0x4ed8aa4a +DATA K256<>+0x1b8(SB)/4, $0x5b9cca4f +DATA K256<>+0x1bc(SB)/4, $0x682e6ff3 + +DATA K256<>+0x1c0(SB)/4, $0x748f82ee +DATA K256<>+0x1c4(SB)/4, $0x78a5636f +DATA K256<>+0x1c8(SB)/4, $0x84c87814 +DATA K256<>+0x1cc(SB)/4, $0x8cc70208 +DATA K256<>+0x1d0(SB)/4, $0x748f82ee +DATA K256<>+0x1d4(SB)/4, $0x78a5636f +DATA K256<>+0x1d8(SB)/4, $0x84c87814 +DATA K256<>+0x1dc(SB)/4, $0x8cc70208 + +DATA K256<>+0x1e0(SB)/4, $0x90befffa +DATA K256<>+0x1e4(SB)/4, $0xa4506ceb +DATA K256<>+0x1e8(SB)/4, $0xbef9a3f7 +DATA K256<>+0x1ec(SB)/4, $0xc67178f2 +DATA K256<>+0x1f0(SB)/4, $0x90befffa +DATA K256<>+0x1f4(SB)/4, $0xa4506ceb +DATA K256<>+0x1f8(SB)/4, $0xbef9a3f7 +DATA K256<>+0x1fc(SB)/4, $0xc67178f2 + +GLOBL K256<>(SB), (NOPTR + RODATA), $512 diff --git a/privacy/zsl/zsl/sha256/sha256block_decl.go b/privacy/zsl/zsl/sha256/sha256block_decl.go new file mode 100644 index 0000000..fe07e53 --- /dev/null +++ b/privacy/zsl/zsl/sha256/sha256block_decl.go @@ -0,0 +1,11 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build 386 amd64 s390x ppc64le + +package sha256 + +//go:noescape + +func block(dig *digest, p []byte) diff --git a/privacy/zsl/zsl/sha256/sha256block_generic.go b/privacy/zsl/zsl/sha256/sha256block_generic.go new file mode 100644 index 0000000..a182a5e --- /dev/null +++ b/privacy/zsl/zsl/sha256/sha256block_generic.go @@ -0,0 +1,9 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build !amd64,!386,!s390x,!ppc64le + +package sha256 + +var block = blockGeneric diff --git a/privacy/zsl/zsl/snark/.gitignore b/privacy/zsl/zsl/snark/.gitignore new file mode 100644 index 0000000..5e164a1 --- /dev/null +++ b/privacy/zsl/zsl/snark/.gitignore @@ -0,0 +1,4 @@ +*.pk +*.vk +*.a +*.o diff --git a/privacy/zsl/zsl/snark/Makefile b/privacy/zsl/zsl/snark/Makefile new file mode 100644 index 0000000..440779c --- /dev/null +++ b/privacy/zsl/zsl/snark/Makefile @@ -0,0 +1,21 @@ +OPTFLAGS = -march=native -mtune=native -O2 +CXXFLAGS += -g -Wall -Wextra -Wno-unused-parameter -std=c++11 -fPIC -Wno-unused-variable +CXXFLAGS += -I./libsnark/ -I./libsnark/src/ -DCURVE_ALT_BN128 -DBINARY_OUTPUT -DMONTGOMERY_OUTPUT -DNO_PT_COMPRESSION=1 -DMULTICORE -fopenmp -DNO_PROCPS +CXXFLAGS += $(OPTFLAGS) +LDFLAGS += -flto + +LDLIBS += -lgmpxx -lgmp -lboost_system -fopenmp + +all: + $(CXX) -o zsl.o -x c++ impl.tcc -c $(CXXFLAGS) + $(CXX) -o alt_bn128_g1.o libsnark/src/algebra/curves/alt_bn128/alt_bn128_g1.cpp -c $(CXXFLAGS) + $(CXX) -o alt_bn128_g2.o libsnark/src/algebra/curves/alt_bn128/alt_bn128_g2.cpp -c $(CXXFLAGS) + $(CXX) -o alt_bn128_init.o libsnark/src/algebra/curves/alt_bn128/alt_bn128_init.cpp -c $(CXXFLAGS) + $(CXX) -o alt_bn128_pairing.o libsnark/src/algebra/curves/alt_bn128/alt_bn128_pairing.cpp -c $(CXXFLAGS) + $(CXX) -o alt_bn128_pp.o libsnark/src/algebra/curves/alt_bn128/alt_bn128_pp.cpp -c $(CXXFLAGS) + $(CXX) -o libsnark_utils.o libsnark/src/common/utils.cpp -c $(CXXFLAGS) + $(CXX) -o libsnark_profiling.o libsnark/src/common/profiling.cpp -c $(CXXFLAGS) + ar -rcs libzsl.a zsl.o alt_bn128_g1.o alt_bn128_g2.o alt_bn128_init.o alt_bn128_pairing.o alt_bn128_pp.o libsnark_utils.o libsnark_profiling.o + +clean: + $(RM) libzsl.a zsl.o libsnark_profiling.o libsnark_utils.o alt_bn128_pp.o alt_bn128_g1.o alt_bn128_g2.o alt_bn128_init.o alt_bn128_pairing.o diff --git a/privacy/zsl/zsl/snark/gadget_tt.cpp b/privacy/zsl/zsl/snark/gadget_tt.cpp new file mode 100644 index 0000000..1b2564e --- /dev/null +++ b/privacy/zsl/zsl/snark/gadget_tt.cpp @@ -0,0 +1,12 @@ +#include +#include + +#include "common/default_types/r1cs_ppzksnark_pp.hpp" +#include "zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.hpp" + + +int main() +{ + std::cout << "proof system test done" << std::endl; + return 0; +} diff --git a/privacy/zsl/zsl/snark/gadgets.tcc b/privacy/zsl/zsl/snark/gadgets.tcc new file mode 100644 index 0000000..6b12b74 --- /dev/null +++ b/privacy/zsl/zsl/snark/gadgets.tcc @@ -0,0 +1,1253 @@ +// Copyright 2017 Zerocoin Electric Coin Company LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "common/default_types/r1cs_ppzksnark_pp.hpp" +#include "zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.hpp" +#include "gadgetlib1/gadgets/hashes/sha256/sha256_gadget.hpp" +#include "gadgetlib1/gadgets/merkle_tree/merkle_tree_check_read_gadget.hpp" + +#include + +template +pb_variable_array from_bits(std::vector bits, pb_variable& ZERO) { + pb_variable_array acc; + + BOOST_FOREACH(bool bit, bits) { + acc.emplace_back(bit ? ONE : ZERO); + } + + return acc; +} + +std::vector convertIntToVectorLE(const uint64_t val_int) { + std::vector bytes; + + for(size_t i = 0; i < 8; i++) { + bytes.push_back(val_int >> (i * 8)); + } + + return bytes; +} + +// Convert bytes into boolean vector. (MSB to LSB) +std::vector convertBytesVectorToVector(const std::vector& bytes) { + std::vector ret; + ret.resize(bytes.size() * 8); + + unsigned char c; + for (size_t i = 0; i < bytes.size(); i++) { + c = bytes.at(i); + for (size_t j = 0; j < 8; j++) { + ret.at((i*8)+j) = (c >> (7-j)) & 1; + } + } + + return ret; +} + +// Convert boolean vector (big endian) to integer +uint64_t convertVectorToInt(const std::vector& v) { + if (v.size() > 64) { + throw std::length_error ("boolean vector can't be larger than 64 bits"); + } + + uint64_t result = 0; + for (size_t i=0; i uint64_to_bool_vector(uint64_t input) { + auto num_bv = convertIntToVectorLE(input); + + return convertBytesVectorToVector(num_bv); +} + +template +class KeyHasher : gadget { +private: + std::shared_ptr> block; + std::shared_ptr> hasher; + +public: + KeyHasher( + protoboard &pb, + pb_variable& ZERO, + pb_variable_array sk, + std::shared_ptr> pk + ) : gadget(pb) { + pb_linear_combination_array IV = SHA256_default_IV(pb); + + pb_variable_array length_padding = + from_bits({ + // padding + 1,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,1, + 0,0,0,0,0,0,0,0 + }, ZERO); + + block.reset(new block_variable(pb, { + sk, + length_padding + }, "")); + + hasher.reset(new sha256_compression_function_gadget( + pb, + IV, + block->bits, + *pk, + "")); + } + + void generate_r1cs_constraints() { + hasher->generate_r1cs_constraints(); + } + + void generate_r1cs_witness() { + hasher->generate_r1cs_witness(); + } +}; + +template +class SendNullifier : gadget { +private: + std::shared_ptr> block; + std::shared_ptr> hasher; + +public: + SendNullifier( + protoboard &pb, + pb_variable& ZERO, + pb_variable_array rho, + std::shared_ptr> result + ) : gadget(pb) { + pb_linear_combination_array IV = SHA256_default_IV(pb); + + pb_variable_array discriminants; + discriminants.emplace_back(ZERO); + discriminants.emplace_back(ZERO); + discriminants.emplace_back(ZERO); + discriminants.emplace_back(ZERO); + discriminants.emplace_back(ZERO); + discriminants.emplace_back(ZERO); + discriminants.emplace_back(ZERO); + discriminants.emplace_back(ZERO); + + pb_variable_array length_padding = + from_bits({ + // padding + 1,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,1, + 0,0,0,0,1,0,0,0 + }, ZERO); + + block.reset(new block_variable(pb, { + discriminants, + rho, + length_padding + }, "")); + + hasher.reset(new sha256_compression_function_gadget( + pb, + IV, + block->bits, + *result, + "")); + } + + void generate_r1cs_constraints() { + hasher->generate_r1cs_constraints(); + } + + void generate_r1cs_witness() { + hasher->generate_r1cs_witness(); + } +}; + +template +class SpendNullifier : gadget { +private: + std::shared_ptr> block1; + std::shared_ptr> hasher1; + std::shared_ptr> intermediate; + std::shared_ptr> block2; + std::shared_ptr> hasher2; + +public: + SpendNullifier( + protoboard &pb, + pb_variable& ZERO, + pb_variable_array rho, + pb_variable_array sk, + std::shared_ptr> result + ) : gadget(pb) { + pb_linear_combination_array IV = SHA256_default_IV(pb); + + pb_variable_array discriminants; + discriminants.emplace_back(ZERO); + discriminants.emplace_back(ZERO); + discriminants.emplace_back(ZERO); + discriminants.emplace_back(ZERO); + discriminants.emplace_back(ZERO); + discriminants.emplace_back(ZERO); + discriminants.emplace_back(ZERO); + discriminants.emplace_back(ONE); + + block1.reset(new block_variable(pb, { + discriminants, + rho, + pb_variable_array(sk.begin(), sk.begin() + 248) + }, "")); + + intermediate.reset(new digest_variable(pb, 256, "")); + + hasher1.reset(new sha256_compression_function_gadget( + pb, + IV, + block1->bits, + *intermediate, + "")); + + pb_variable_array length_padding = + from_bits({ + // padding + 1,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,1,0, + 0,0,0,0,1,0,0,0 + }, ZERO); + + block2.reset(new block_variable(pb, { + pb_variable_array(sk.begin() + 248, sk.end()), + length_padding + }, "")); + + pb_linear_combination_array IV2(intermediate->bits); + + hasher2.reset(new sha256_compression_function_gadget( + pb, + IV2, + block2->bits, + *result, + "")); + } + + void generate_r1cs_constraints() { + hasher1->generate_r1cs_constraints(); + hasher2->generate_r1cs_constraints(); + } + + void generate_r1cs_witness() { + hasher1->generate_r1cs_witness(); + hasher2->generate_r1cs_witness(); + } +}; + +template +class NoteCommitment : gadget { +private: + std::shared_ptr> block1; + std::shared_ptr> hasher1; + std::shared_ptr> intermediate; + std::shared_ptr> block2; + std::shared_ptr> hasher2; + +public: + NoteCommitment( + protoboard &pb, + pb_variable& ZERO, + pb_variable_array rho, + pb_variable_array pk, + pb_variable_array value, + std::shared_ptr> result + ) : gadget(pb) { + pb_linear_combination_array IV = SHA256_default_IV(pb); + + block1.reset(new block_variable(pb, { + rho, + pk + }, "")); + + intermediate.reset(new digest_variable(pb, 256, "")); + + hasher1.reset(new sha256_compression_function_gadget( + pb, + IV, + block1->bits, + *intermediate, + "")); + + pb_variable_array length_padding = + from_bits({ + // padding + 1,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,1,0, + 0,1,0,0,0,0,0,0 + }, ZERO); + + block2.reset(new block_variable(pb, { + value, + length_padding + }, "")); + + pb_linear_combination_array IV2(intermediate->bits); + + hasher2.reset(new sha256_compression_function_gadget( + pb, + IV2, + block2->bits, + *result, + "")); + } + + void generate_r1cs_constraints() { + hasher1->generate_r1cs_constraints(); + hasher2->generate_r1cs_constraints(); + } + + void generate_r1cs_witness() { + hasher1->generate_r1cs_witness(); + hasher2->generate_r1cs_witness(); + } +}; + +template +class ShieldingCircuit : gadget { +private: + // Verifier inputs + pb_variable_array zk_packed_inputs; + pb_variable_array zk_unpacked_inputs; + std::shared_ptr> unpacker; + + // SHA256(0x00 | rho) + std::shared_ptr> send_nullifier; + // The note commitment: SHA256(rho | pk | value) + std::shared_ptr> cm; + // 64-bit value + pb_variable_array value; + + // Aux inputs + pb_variable ZERO; + std::shared_ptr> rho; + std::shared_ptr> pk; + + // Note commitment hasher + std::shared_ptr> cm_hasher; + + // Send nullifier hasher + std::shared_ptr> nf_hasher; + +public: + ShieldingCircuit(protoboard &pb) : gadget(pb) { + // Inputs + { + zk_packed_inputs.allocate(pb, verifying_field_element_size()); + pb.set_input_sizes(verifying_field_element_size()); + + send_nullifier.reset(new digest_variable(pb, 256, "")); + zk_unpacked_inputs.insert(zk_unpacked_inputs.end(), send_nullifier->bits.begin(), send_nullifier->bits.end()); + + cm.reset(new digest_variable(pb, 256, "")); + zk_unpacked_inputs.insert(zk_unpacked_inputs.end(), cm->bits.begin(), cm->bits.end()); + + value.allocate(pb, 64, ""); + zk_unpacked_inputs.insert(zk_unpacked_inputs.end(), value.begin(), value.end()); + + assert(zk_unpacked_inputs.size() == verifying_input_bit_size()); + + unpacker.reset(new multipacking_gadget( + pb, + zk_unpacked_inputs, + zk_packed_inputs, + FieldT::capacity(), + "unpacker" + )); + } + + // Aux + ZERO.allocate(pb); + rho.reset(new digest_variable(pb, 256, "")); + pk.reset(new digest_variable(pb, 256, "")); + + cm_hasher.reset(new NoteCommitment(pb, ZERO, rho->bits, pk->bits, value, cm)); + nf_hasher.reset(new SendNullifier(pb, ZERO, rho->bits, send_nullifier)); + } + + void generate_r1cs_constraints() { + unpacker->generate_r1cs_constraints(true); + generate_r1cs_equals_const_constraint(this->pb, ZERO, FieldT::zero(), "ZERO"); + + rho->generate_r1cs_constraints(); + pk->generate_r1cs_constraints(); + + cm_hasher->generate_r1cs_constraints(); + nf_hasher->generate_r1cs_constraints(); + } + + void generate_r1cs_witness( + const std::vector& witness_rho, + const std::vector& witness_pk, + uint64_t witness_value + ) { + this->pb.val(ZERO) = FieldT::zero(); + + rho->bits.fill_with_bits( + this->pb, + convertBytesVectorToVector(witness_rho) + ); + + pk->bits.fill_with_bits( + this->pb, + convertBytesVectorToVector(witness_pk) + ); + + value.fill_with_bits( + this->pb, + uint64_to_bool_vector(witness_value) + ); + + cm_hasher->generate_r1cs_witness(); + nf_hasher->generate_r1cs_witness(); + + unpacker->generate_r1cs_witness_from_bits(); + } + + static r1cs_primary_input witness_map( + const std::vector &witness_nf, + const std::vector &witness_cm, + uint64_t witness_value + ) { + std::vector verify_inputs; + + std::vector nf_bits = convertBytesVectorToVector(witness_nf); + std::vector cm_bits = convertBytesVectorToVector(witness_cm); + std::vector value_bits = uint64_to_bool_vector(witness_value); + + verify_inputs.insert(verify_inputs.end(), nf_bits.begin(), nf_bits.end()); + verify_inputs.insert(verify_inputs.end(), cm_bits.begin(), cm_bits.end()); + verify_inputs.insert(verify_inputs.end(), value_bits.begin(), value_bits.end()); + + assert(verify_inputs.size() == verifying_input_bit_size()); + auto verify_field_elements = pack_bit_vector_into_field_element_vector(verify_inputs); + assert(verify_field_elements.size() == verifying_field_element_size()); + return verify_field_elements; + } + + static size_t verifying_field_element_size() { + return div_ceil(verifying_input_bit_size(), FieldT::capacity()); + } + + static size_t verifying_input_bit_size() { + size_t acc = 0; + + acc += 256; // the nullifier + acc += 256; // the note commitment + acc += 64; // the value of the note + + return acc; + } +}; + +#define INCREMENTAL_MERKLE_TREE_DEPTH 29 + +template +class merkle_tree_gadget : gadget { +private: + typedef sha256_two_to_one_hash_gadget sha256_gadget; + + pb_variable_array positions; + std::shared_ptr> authvars; + std::shared_ptr> auth; + +public: + merkle_tree_gadget( + protoboard& pb, + digest_variable leaf, + digest_variable root, + pb_variable& enforce + ) : gadget(pb) { + positions.allocate(pb, INCREMENTAL_MERKLE_TREE_DEPTH); + authvars.reset(new merkle_authentication_path_variable( + pb, INCREMENTAL_MERKLE_TREE_DEPTH, "auth" + )); + auth.reset(new merkle_tree_check_read_gadget( + pb, + INCREMENTAL_MERKLE_TREE_DEPTH, + positions, + leaf, + root, + *authvars, + enforce, + "" + )); + } + + void generate_r1cs_constraints() { + for (size_t i = 0; i < INCREMENTAL_MERKLE_TREE_DEPTH; i++) { + generate_boolean_r1cs_constraint( + this->pb, + positions[i], + "boolean_positions" + ); + } + + authvars->generate_r1cs_constraints(); + auth->generate_r1cs_constraints(); + } + + void generate_r1cs_witness( + size_t path_index, + const std::vector>& authentication_path + ) { + positions.fill_with_bits_of_ulong(this->pb, path_index); + + authvars->generate_r1cs_witness(path_index, authentication_path); + auth->generate_r1cs_witness(); + } +}; + +template +class UnshieldingCircuit : gadget { +private: + // Verifier inputs + pb_variable_array zk_packed_inputs; + pb_variable_array zk_unpacked_inputs; + std::shared_ptr> unpacker; + + // 64-bit value + pb_variable_array value; + + // Aux inputs + pb_variable ZERO; + std::shared_ptr> cm; // Note commitment + std::shared_ptr> rho; + std::shared_ptr> pk; + std::shared_ptr> sk; + + // Key hasher + std::shared_ptr> key_hasher; + + // Note commitment hasher + std::shared_ptr> cm_hasher; + + // Spend nullifier hasher + std::shared_ptr> nf_hasher; + + // Merkle tree lookup + std::shared_ptr> merkle_lookup; + +public: + // The anchor of the tree + std::shared_ptr> anchor; + + // SHA256(0x01 | rho) + std::shared_ptr> spend_nullifier; + + UnshieldingCircuit(protoboard &pb) : gadget(pb) { + // Inputs + { + zk_packed_inputs.allocate(pb, verifying_field_element_size()); + pb.set_input_sizes(verifying_field_element_size()); + + spend_nullifier.reset(new digest_variable(pb, 256, "")); + zk_unpacked_inputs.insert(zk_unpacked_inputs.end(), spend_nullifier->bits.begin(), spend_nullifier->bits.end()); + + anchor.reset(new digest_variable(pb, 256, "")); + zk_unpacked_inputs.insert(zk_unpacked_inputs.end(), anchor->bits.begin(), anchor->bits.end()); + + value.allocate(pb, 64, ""); + zk_unpacked_inputs.insert(zk_unpacked_inputs.end(), value.begin(), value.end()); + + assert(zk_unpacked_inputs.size() == verifying_input_bit_size()); + + unpacker.reset(new multipacking_gadget( + pb, + zk_unpacked_inputs, + zk_packed_inputs, + FieldT::capacity(), + "unpacker" + )); + } + + // Aux + ZERO.allocate(pb); + rho.reset(new digest_variable(pb, 256, "")); + sk.reset(new digest_variable(pb, 256, "")); + pk.reset(new digest_variable(pb, 256, "")); + cm.reset(new digest_variable(pb, 256, "")); + + key_hasher.reset(new KeyHasher(pb, ZERO, sk->bits, pk)); + cm_hasher.reset(new NoteCommitment(pb, ZERO, rho->bits, pk->bits, value, cm)); + nf_hasher.reset(new SpendNullifier(pb, ZERO, rho->bits, sk->bits, spend_nullifier)); + auto test = ONE; + merkle_lookup.reset(new merkle_tree_gadget(pb, *cm, *anchor, test)); + } + + void generate_r1cs_constraints() { + unpacker->generate_r1cs_constraints(true); + generate_r1cs_equals_const_constraint(this->pb, ZERO, FieldT::zero(), "ZERO"); + + rho->generate_r1cs_constraints(); + sk->generate_r1cs_constraints(); + + key_hasher->generate_r1cs_constraints(); + cm_hasher->generate_r1cs_constraints(); + nf_hasher->generate_r1cs_constraints(); + merkle_lookup->generate_r1cs_constraints(); + } + + void generate_r1cs_witness( + const std::vector& witness_rho, + const std::vector& witness_sk, + uint64_t witness_value, + size_t path_index, + const std::vector>& authentication_path + ) { + this->pb.val(ZERO) = FieldT::zero(); + + rho->bits.fill_with_bits( + this->pb, + convertBytesVectorToVector(witness_rho) + ); + + sk->bits.fill_with_bits( + this->pb, + convertBytesVectorToVector(witness_sk) + ); + + value.fill_with_bits( + this->pb, + uint64_to_bool_vector(witness_value) + ); + + key_hasher->generate_r1cs_witness(); + cm_hasher->generate_r1cs_witness(); + nf_hasher->generate_r1cs_witness(); + merkle_lookup->generate_r1cs_witness(path_index, authentication_path); + + unpacker->generate_r1cs_witness_from_bits(); + } + + static r1cs_primary_input witness_map( + const std::vector &witness_nf, + const std::vector &witness_anchor, + uint64_t witness_value + ) { + std::vector verify_inputs; + + std::vector nf_bits = convertBytesVectorToVector(witness_nf); + std::vector anchor_bits = convertBytesVectorToVector(witness_anchor); + std::vector value_bits = uint64_to_bool_vector(witness_value); + + verify_inputs.insert(verify_inputs.end(), nf_bits.begin(), nf_bits.end()); + verify_inputs.insert(verify_inputs.end(), anchor_bits.begin(), anchor_bits.end()); + verify_inputs.insert(verify_inputs.end(), value_bits.begin(), value_bits.end()); + + assert(verify_inputs.size() == verifying_input_bit_size()); + auto verify_field_elements = pack_bit_vector_into_field_element_vector(verify_inputs); + assert(verify_field_elements.size() == verifying_field_element_size()); + return verify_field_elements; + } + + static size_t verifying_field_element_size() { + return div_ceil(verifying_input_bit_size(), FieldT::capacity()); + } + + static size_t verifying_input_bit_size() { + size_t acc = 0; + + acc += 256; // the nullifier + acc += 256; // the anchor + acc += 64; // the value of the note + + return acc; + } +}; + +template +T swap_endianness_u64(T v) { + if (v.size() != 64) { + throw std::length_error("invalid bit length for 64-bit unsigned integer"); + } + + for (size_t i = 0; i < 4; i++) { + for (size_t j = 0; j < 8; j++) { + std::swap(v[i*8 + j], v[((7-i)*8)+j]); + } + } + + return v; +} + +template +linear_combination packed_addition(pb_variable_array input) { + auto input_swapped = swap_endianness_u64(input); + + return pb_packing_sum(pb_variable_array( + input_swapped.rbegin(), input_swapped.rend() + )); +} + +template +class TransferCircuit : gadget { +private: + // Verifier inputs + pb_variable_array zk_packed_inputs; + pb_variable_array zk_unpacked_inputs; + std::shared_ptr> unpacker; + + // Aux inputs + pb_variable ZERO; + + // Verifier inputs + std::shared_ptr> anchor; + std::shared_ptr> spend_nullifier_input_1; + std::shared_ptr> spend_nullifier_input_2; + std::shared_ptr> send_nullifier_output_1; + std::shared_ptr> send_nullifier_output_2; + + // Input stuff. + std::shared_ptr> input_sk_1; + std::shared_ptr> input_sk_2; + std::shared_ptr> input_pk_1; + std::shared_ptr> input_pk_2; + std::shared_ptr> key_hasher_1; + std::shared_ptr> key_hasher_2; + std::shared_ptr> input_rho_1; + std::shared_ptr> input_rho_2; + std::shared_ptr> input_nf_hasher_1; + std::shared_ptr> input_nf_hasher_2; + pb_variable_array input_value_1; + pb_variable_array input_value_2; + std::shared_ptr> input_cm_1; + std::shared_ptr> input_cm_2; + std::shared_ptr> input_cm_hasher_1; + std::shared_ptr> input_cm_hasher_2; + pb_variable enforce_input_1; + pb_variable enforce_input_2; + std::shared_ptr> merkle_lookup_1; + std::shared_ptr> merkle_lookup_2; + + // Output stuff. + std::shared_ptr> output_cm_1; + pb_variable_array output_value_1; + std::shared_ptr> output_rho_1; + std::shared_ptr> output_pk_1; + std::shared_ptr> output_cm_hasher_1; + std::shared_ptr> output_nf_hasher_1; + + std::shared_ptr> output_cm_2; + pb_variable_array output_value_2; + std::shared_ptr> output_rho_2; + std::shared_ptr> output_pk_2; + std::shared_ptr> output_cm_hasher_2; + std::shared_ptr> output_nf_hasher_2; + +public: + + TransferCircuit(protoboard &pb) : gadget(pb) { + // Inputs + { + zk_packed_inputs.allocate(pb, verifying_field_element_size()); + pb.set_input_sizes(verifying_field_element_size()); + + anchor.reset(new digest_variable(pb, 256, "")); + zk_unpacked_inputs.insert(zk_unpacked_inputs.end(), anchor->bits.begin(), anchor->bits.end()); + + spend_nullifier_input_1.reset(new digest_variable(pb, 256, "")); + zk_unpacked_inputs.insert(zk_unpacked_inputs.end(), spend_nullifier_input_1->bits.begin(), spend_nullifier_input_1->bits.end()); + + spend_nullifier_input_2.reset(new digest_variable(pb, 256, "")); + zk_unpacked_inputs.insert(zk_unpacked_inputs.end(), spend_nullifier_input_2->bits.begin(), spend_nullifier_input_2->bits.end()); + + send_nullifier_output_1.reset(new digest_variable(pb, 256, "")); + zk_unpacked_inputs.insert(zk_unpacked_inputs.end(), send_nullifier_output_1->bits.begin(), send_nullifier_output_1->bits.end()); + + send_nullifier_output_2.reset(new digest_variable(pb, 256, "")); + zk_unpacked_inputs.insert(zk_unpacked_inputs.end(), send_nullifier_output_2->bits.begin(), send_nullifier_output_2->bits.end()); + + output_cm_1.reset(new digest_variable(pb, 256, "")); + zk_unpacked_inputs.insert(zk_unpacked_inputs.end(), output_cm_1->bits.begin(), output_cm_1->bits.end()); + + output_cm_2.reset(new digest_variable(pb, 256, "")); + zk_unpacked_inputs.insert(zk_unpacked_inputs.end(), output_cm_2->bits.begin(), output_cm_2->bits.end()); + + assert(zk_unpacked_inputs.size() == verifying_input_bit_size()); + + unpacker.reset(new multipacking_gadget( + pb, + zk_unpacked_inputs, + zk_packed_inputs, + FieldT::capacity(), + "unpacker" + )); + } + + // Aux + ZERO.allocate(pb); + input_cm_1.reset(new digest_variable(pb, 256, "")); + input_cm_2.reset(new digest_variable(pb, 256, "")); + input_sk_1.reset(new digest_variable(pb, 256, "")); + input_sk_2.reset(new digest_variable(pb, 256, "")); + input_pk_1.reset(new digest_variable(pb, 256, "")); + input_pk_2.reset(new digest_variable(pb, 256, "")); + input_rho_1.reset(new digest_variable(pb, 256, "")); + input_rho_2.reset(new digest_variable(pb, 256, "")); + key_hasher_1.reset(new KeyHasher(pb, ZERO, input_sk_1->bits, input_pk_1)); + key_hasher_2.reset(new KeyHasher(pb, ZERO, input_sk_2->bits, input_pk_2)); + input_nf_hasher_1.reset(new SpendNullifier(pb, ZERO, input_rho_1->bits, input_sk_1->bits, spend_nullifier_input_1)); + input_nf_hasher_2.reset(new SpendNullifier(pb, ZERO, input_rho_2->bits, input_sk_2->bits, spend_nullifier_input_2)); + + input_value_1.allocate(pb, 64, ""); + input_value_2.allocate(pb, 64, ""); + + input_cm_hasher_1.reset(new NoteCommitment(pb, ZERO, input_rho_1->bits, input_pk_1->bits, input_value_1, input_cm_1)); + input_cm_hasher_2.reset(new NoteCommitment(pb, ZERO, input_rho_2->bits, input_pk_2->bits, input_value_2, input_cm_2)); + + enforce_input_1.allocate(pb); + enforce_input_2.allocate(pb); + + merkle_lookup_1.reset(new merkle_tree_gadget(pb, *input_cm_1, *anchor, enforce_input_1)); + merkle_lookup_2.reset(new merkle_tree_gadget(pb, *input_cm_2, *anchor, enforce_input_2)); + + output_value_1.allocate(pb, 64, ""); + output_value_2.allocate(pb, 64, ""); + + output_rho_1.reset(new digest_variable(pb, 256, "")); + output_rho_2.reset(new digest_variable(pb, 256, "")); + output_pk_1.reset(new digest_variable(pb, 256, "")); + output_pk_2.reset(new digest_variable(pb, 256, "")); + + output_cm_hasher_1.reset(new NoteCommitment(pb, ZERO, output_rho_1->bits, output_pk_1->bits, output_value_1, output_cm_1)); + output_cm_hasher_2.reset(new NoteCommitment(pb, ZERO, output_rho_2->bits, output_pk_2->bits, output_value_2, output_cm_2)); + + output_nf_hasher_1.reset(new SendNullifier(pb, ZERO, output_rho_1->bits, send_nullifier_output_1)); + output_nf_hasher_2.reset(new SendNullifier(pb, ZERO, output_rho_2->bits, send_nullifier_output_2)); + } + + void generate_r1cs_constraints() { + unpacker->generate_r1cs_constraints(true); + generate_r1cs_equals_const_constraint(this->pb, ZERO, FieldT::zero(), "ZERO"); + + input_sk_1->generate_r1cs_constraints(); + input_sk_2->generate_r1cs_constraints(); + input_rho_1->generate_r1cs_constraints(); + input_rho_2->generate_r1cs_constraints(); + key_hasher_1->generate_r1cs_constraints(); + key_hasher_2->generate_r1cs_constraints(); + input_nf_hasher_1->generate_r1cs_constraints(); + input_nf_hasher_2->generate_r1cs_constraints(); + + for (size_t i = 0; i < 64; i++) { + generate_boolean_r1cs_constraint( + this->pb, + input_value_1[i], + "" + ); + generate_boolean_r1cs_constraint( + this->pb, + input_value_2[i], + "" + ); + } + + input_cm_hasher_1->generate_r1cs_constraints(); + input_cm_hasher_2->generate_r1cs_constraints(); + + generate_boolean_r1cs_constraint(this->pb, enforce_input_1, ""); + + this->pb.add_r1cs_constraint(r1cs_constraint( + packed_addition(input_value_1), + (1 - enforce_input_1), + 0 + ), ""); + + generate_boolean_r1cs_constraint(this->pb, enforce_input_2, ""); + + this->pb.add_r1cs_constraint(r1cs_constraint( + packed_addition(input_value_2), + (1 - enforce_input_2), + 0 + ), ""); + + merkle_lookup_1->generate_r1cs_constraints(); + merkle_lookup_2->generate_r1cs_constraints(); + + for (size_t i = 0; i < 64; i++) { + generate_boolean_r1cs_constraint( + this->pb, + output_value_1[i], + "" + ); + generate_boolean_r1cs_constraint( + this->pb, + output_value_2[i], + "" + ); + } + + output_rho_1->generate_r1cs_constraints(); + output_rho_2->generate_r1cs_constraints(); + output_pk_1->generate_r1cs_constraints(); + output_pk_2->generate_r1cs_constraints(); + + output_cm_hasher_1->generate_r1cs_constraints(); + output_cm_hasher_2->generate_r1cs_constraints(); + + output_nf_hasher_1->generate_r1cs_constraints(); + output_nf_hasher_2->generate_r1cs_constraints(); + + { + linear_combination left_side = + packed_addition(input_value_1) + packed_addition(input_value_2); + + linear_combination right_side = + packed_addition(output_value_1) + packed_addition(output_value_2); + + // Ensure that both sides are equal + this->pb.add_r1cs_constraint(r1cs_constraint( + left_side, + 1, + right_side + )); + } + } + + void generate_r1cs_witness( + const std::vector& witness_rho_1, + const std::vector& witness_sk_1, + uint64_t witness_value_1, + size_t path_index_1, + const std::vector>& authentication_path_1, + const std::vector& witness_rho_2, + const std::vector& witness_sk_2, + uint64_t witness_value_2, + size_t path_index_2, + const std::vector>& authentication_path_2, + const std::vector& output_witness_rho_1, + const std::vector& output_witness_pk_1, + uint64_t output_witness_value_1, + const std::vector& output_witness_rho_2, + const std::vector& output_witness_pk_2, + uint64_t output_witness_value_2 + ) { + this->pb.val(ZERO) = FieldT::zero(); + + this->pb.val(enforce_input_1) = (witness_value_1 != 0) ? FieldT::one() : FieldT::zero(); + this->pb.val(enforce_input_2) = (witness_value_2 != 0) ? FieldT::one() : FieldT::zero(); + + input_rho_1->bits.fill_with_bits( + this->pb, + convertBytesVectorToVector(witness_rho_1) + ); + + input_sk_1->bits.fill_with_bits( + this->pb, + convertBytesVectorToVector(witness_sk_1) + ); + + input_value_1.fill_with_bits( + this->pb, + uint64_to_bool_vector(witness_value_1) + ); + + key_hasher_1->generate_r1cs_witness(); + input_cm_hasher_1->generate_r1cs_witness(); + input_nf_hasher_1->generate_r1cs_witness(); + merkle_lookup_1->generate_r1cs_witness(path_index_1, authentication_path_1); + + input_rho_2->bits.fill_with_bits( + this->pb, + convertBytesVectorToVector(witness_rho_2) + ); + + input_sk_2->bits.fill_with_bits( + this->pb, + convertBytesVectorToVector(witness_sk_2) + ); + + input_value_2.fill_with_bits( + this->pb, + uint64_to_bool_vector(witness_value_2) + ); + + key_hasher_2->generate_r1cs_witness(); + input_cm_hasher_2->generate_r1cs_witness(); + input_nf_hasher_2->generate_r1cs_witness(); + merkle_lookup_2->generate_r1cs_witness(path_index_2, authentication_path_2); + + output_rho_1->bits.fill_with_bits( + this->pb, + convertBytesVectorToVector(output_witness_rho_1) + ); + + output_pk_1->bits.fill_with_bits( + this->pb, + convertBytesVectorToVector(output_witness_pk_1) + ); + + output_value_1.fill_with_bits( + this->pb, + uint64_to_bool_vector(output_witness_value_1) + ); + + output_cm_hasher_1->generate_r1cs_witness(); + output_nf_hasher_1->generate_r1cs_witness(); + + output_rho_2->bits.fill_with_bits( + this->pb, + convertBytesVectorToVector(output_witness_rho_2) + ); + + output_pk_2->bits.fill_with_bits( + this->pb, + convertBytesVectorToVector(output_witness_pk_2) + ); + + output_value_2.fill_with_bits( + this->pb, + uint64_to_bool_vector(output_witness_value_2) + ); + + output_cm_hasher_2->generate_r1cs_witness(); + output_nf_hasher_2->generate_r1cs_witness(); + + unpacker->generate_r1cs_witness_from_bits(); + } + + static r1cs_primary_input witness_map( + const std::vector &witness_anchor, + const std::vector &input_nf_1, + const std::vector &input_nf_2, + const std::vector &output_nf_1, + const std::vector &output_nf_2, + const std::vector &output_cm_1, + const std::vector &output_cm_2 + ) + { + std::vector verify_inputs; + + std::vector anchor_bits = convertBytesVectorToVector(witness_anchor); + std::vector input_nf1_bits = convertBytesVectorToVector(input_nf_1); + std::vector input_nf2_bits = convertBytesVectorToVector(input_nf_2); + std::vector output_nf1_bits = convertBytesVectorToVector(output_nf_1); + std::vector output_nf2_bits = convertBytesVectorToVector(output_nf_2); + std::vector output_cm1_bits = convertBytesVectorToVector(output_cm_1); + std::vector output_cm2_bits = convertBytesVectorToVector(output_cm_2); + + verify_inputs.insert(verify_inputs.end(), anchor_bits.begin(), anchor_bits.end()); + verify_inputs.insert(verify_inputs.end(), input_nf1_bits.begin(), input_nf1_bits.end()); + verify_inputs.insert(verify_inputs.end(), input_nf2_bits.begin(), input_nf2_bits.end()); + verify_inputs.insert(verify_inputs.end(), output_nf1_bits.begin(), output_nf1_bits.end()); + verify_inputs.insert(verify_inputs.end(), output_nf2_bits.begin(), output_nf2_bits.end()); + verify_inputs.insert(verify_inputs.end(), output_cm1_bits.begin(), output_cm1_bits.end()); + verify_inputs.insert(verify_inputs.end(), output_cm2_bits.begin(), output_cm2_bits.end()); + + assert(verify_inputs.size() == verifying_input_bit_size()); + auto verify_field_elements = pack_bit_vector_into_field_element_vector(verify_inputs); + assert(verify_field_elements.size() == verifying_field_element_size()); + return verify_field_elements; + } + + static size_t verifying_field_element_size() { + return div_ceil(verifying_input_bit_size(), FieldT::capacity()); + } + + static size_t verifying_input_bit_size() { + size_t acc = 0; + + acc += 256; // the anchor + acc += 256; // input 1 nullifier + acc += 256; // input 2 nullifier + acc += 256; // output 1 nullifier + acc += 256; // output 2 nullifier + acc += 256; // output 1 commitment + acc += 256; // output 2 commitment + + return acc; + } +}; diff --git a/privacy/zsl/zsl/snark/impl.tcc b/privacy/zsl/zsl/snark/impl.tcc new file mode 100644 index 0000000..9d970a4 --- /dev/null +++ b/privacy/zsl/zsl/snark/impl.tcc @@ -0,0 +1,427 @@ +// Copyright 2017 Zerocoin Electric Coin Company LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "zsl.h" +#include + +#include +#include "gadgetlib1/gadgets/basic_gadgets.hpp" +#include "zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.hpp" +#include "common/default_types/r1cs_ppzksnark_pp.hpp" +#include "common/utils.hpp" +#include "common/profiling.hpp" + +using namespace libsnark; +using namespace std; + +#include "gadgets.tcc" + +typedef Fr FieldT; + +#include + +template +void saveToFile(std::string path, T& obj) { + std::stringstream ss; + ss << obj; + std::ofstream fh; + fh.open(path, std::ios::binary); + ss.rdbuf()->pubseekpos(0, std::ios_base::out); + fh << ss.rdbuf(); + fh.flush(); + fh.close(); +} + +template +void loadFromFile(std::string path, T& objIn) { + std::stringstream ss; + std::ifstream fh(path, std::ios::binary); + + ss << fh.rdbuf(); + fh.close(); + + ss.rdbuf()->pubseekpos(0, std::ios_base::in); + + ss >> objIn; +} + +void zsl_initialize() +{ + default_r1cs_ppzksnark_pp::init_public_params(); + inhibit_profiling_info = true; + inhibit_profiling_counters = true; +} + +bool zsl_verify_shielding( + void *proof_ptr, + void *send_nf_ptr, + void *cm_ptr, + uint64_t value +) +{ + unsigned char *send_nf = reinterpret_cast(send_nf_ptr); + unsigned char *cm = reinterpret_cast(cm_ptr); + unsigned char *proof = reinterpret_cast(proof_ptr); + + std::vector proof_v(proof, proof+584); + + /*for(int i=0;i<32;i++) printf("%02x", send_nf[i]); + printf("\n"); + for(int i=0;i<32;i++) printf("%02x", cm[i]); + printf("\n"); + for(int i=0;i<584;i++) printf("%02x", proof[i]); + printf("\n"); + */ + std::stringstream proof_data; + for (int i = 0; i < 584; i++) { + proof_data << proof_v[i]; + } + + assert(proof_data.str().size() == 584); + + proof_data.rdbuf()->pubseekpos(0, std::ios_base::in); + + r1cs_ppzksnark_proof proof_obj; + proof_data >> proof_obj; + + auto witness_map = ShieldingCircuit::witness_map( + std::vector(send_nf, send_nf+32), + std::vector(cm, cm+32), + value + ); + + r1cs_ppzksnark_verification_key verification_key; + loadFromFile("shielding.vk", verification_key); + + if (!r1cs_ppzksnark_verifier_strong_IC(verification_key, witness_map, proof_obj)) { + return false; + } else { + return true; + } +} + +bool zsl_verify_unshielding( + void *proof_ptr, + void *spend_nf_ptr, + void *rt_ptr, + uint64_t value +) +{ + unsigned char *spend_nf = reinterpret_cast(spend_nf_ptr); + unsigned char *rt = reinterpret_cast(rt_ptr); + unsigned char *proof = reinterpret_cast(proof_ptr); + + std::vector proof_v(proof, proof+584); + + std::stringstream proof_data; + for (int i = 0; i < 584; i++) { + proof_data << proof_v[i]; + } + + assert(proof_data.str().size() == 584); + + proof_data.rdbuf()->pubseekpos(0, std::ios_base::in); + + r1cs_ppzksnark_proof proof_obj; + proof_data >> proof_obj; + + auto witness_map = UnshieldingCircuit::witness_map( + std::vector(spend_nf, spend_nf+32), + std::vector(rt, rt+32), + value + ); + + r1cs_ppzksnark_verification_key verification_key; + loadFromFile("unshielding.vk", verification_key); + + if (!r1cs_ppzksnark_verifier_strong_IC(verification_key, witness_map, proof_obj)) { + return false; + } else { + return true; + } +} + +void zsl_prove_unshielding( + void *rho_ptr, + void *pk_ptr, + uint64_t value, + uint64_t tree_position, + void *authentication_path_ptr, + void *output_proof_ptr +) +{ + unsigned char *rho = reinterpret_cast(rho_ptr); + unsigned char *pk = reinterpret_cast(pk_ptr); + unsigned char *output_proof = reinterpret_cast(output_proof_ptr); + unsigned char *authentication_path = reinterpret_cast(authentication_path_ptr); + + protoboard pb; + UnshieldingCircuit g(pb); + g.generate_r1cs_constraints(); + + std::vector> auth_path; + for (int i = 0; i < 29; i++) { + auth_path.push_back(convertBytesVectorToVector(std::vector(authentication_path + i*32, authentication_path + i*32 + 32))); + } + + std::reverse(std::begin(auth_path), std::end(auth_path)); + + g.generate_r1cs_witness( + std::vector(rho, rho + 32), + std::vector(pk, pk + 32), + value, + tree_position, + auth_path + ); + pb.constraint_system.swap_AB_if_beneficial(); + assert(pb.is_satisfied()); + + r1cs_ppzksnark_proving_key proving_key; + loadFromFile("unshielding.pk", proving_key); + + auto proof = r1cs_ppzksnark_prover(proving_key, pb.primary_input(), pb.auxiliary_input(), pb.constraint_system); + + std::stringstream proof_data; + proof_data << proof; + auto proof_str = proof_data.str(); + assert(proof_str.size() == 584); + + for (int i = 0; i < 584; i++) { + output_proof[i] = proof_str[i]; + } +} + +void zsl_prove_shielding( + void *rho_ptr, + void *pk_ptr, + uint64_t value, + void *output_proof_ptr +) +{ + unsigned char *rho = reinterpret_cast(rho_ptr); + unsigned char *pk = reinterpret_cast(pk_ptr); + unsigned char *output_proof = reinterpret_cast(output_proof_ptr); + + protoboard pb; + ShieldingCircuit g(pb); + g.generate_r1cs_constraints(); + g.generate_r1cs_witness( + // rho + std::vector(rho, rho + 32), + // pk + std::vector(pk, pk + 32), + // value + value + ); + pb.constraint_system.swap_AB_if_beneficial(); + assert(pb.is_satisfied()); + + r1cs_ppzksnark_proving_key proving_key; + loadFromFile("shielding.pk", proving_key); + + auto proof = r1cs_ppzksnark_prover(proving_key, pb.primary_input(), pb.auxiliary_input(), pb.constraint_system); + + std::stringstream proof_data; + proof_data << proof; + auto proof_str = proof_data.str(); + assert(proof_str.size() == 584); + + for (int i = 0; i < 584; i++) { + output_proof[i] = proof_str[i]; + } +} + +bool zsl_verify_transfer( + void *proof_ptr, + void *anchor_ptr, + void *spend_nf_ptr_1, + void *spend_nf_ptr_2, + void *send_nf_ptr_1, + void *send_nf_ptr_2, + void *cm_ptr_1, + void *cm_ptr_2 +) +{ + unsigned char *anchor = reinterpret_cast(anchor_ptr); + unsigned char *spend_nf_1 = reinterpret_cast(spend_nf_ptr_1); + unsigned char *spend_nf_2 = reinterpret_cast(spend_nf_ptr_2); + unsigned char *send_nf_1 = reinterpret_cast(send_nf_ptr_1); + unsigned char *send_nf_2 = reinterpret_cast(send_nf_ptr_2); + unsigned char *cm_1 = reinterpret_cast(cm_ptr_1); + unsigned char *cm_2 = reinterpret_cast(cm_ptr_2); + unsigned char *proof = reinterpret_cast(proof_ptr); + + std::vector proof_v(proof, proof+584); + + std::stringstream proof_data; + for (int i = 0; i < 584; i++) { + proof_data << proof_v[i]; + } + + assert(proof_data.str().size() == 584); + + proof_data.rdbuf()->pubseekpos(0, std::ios_base::in); + + r1cs_ppzksnark_proof proof_obj; + proof_data >> proof_obj; + + auto witness_map = TransferCircuit::witness_map( + std::vector(anchor, anchor+32), + std::vector(spend_nf_1, spend_nf_1+32), + std::vector(spend_nf_2, spend_nf_2+32), + std::vector(send_nf_1, send_nf_1+32), + std::vector(send_nf_2, send_nf_2+32), + std::vector(cm_1, cm_1+32), + std::vector(cm_2, cm_2+32) + ); + + r1cs_ppzksnark_verification_key verification_key; + loadFromFile("transfer.vk", verification_key); + + if (!r1cs_ppzksnark_verifier_strong_IC(verification_key, witness_map, proof_obj)) { + return false; + } else { + return true; + } +} + +void zsl_prove_transfer( + void *output_proof_ptr, + void *input_rho_ptr_1, + void *input_pk_ptr_1, + uint64_t input_value_1, + uint64_t input_tree_position_1, + void *input_authentication_path_ptr_1, + void *input_rho_ptr_2, + void *input_pk_ptr_2, + uint64_t input_value_2, + uint64_t input_tree_position_2, + void *input_authentication_path_ptr_2, + void *output_rho_ptr_1, + void *output_pk_ptr_1, + uint64_t output_value_1, + void *output_rho_ptr_2, + void *output_pk_ptr_2, + uint64_t output_value_2 +) +{ + unsigned char *output_proof = reinterpret_cast(output_proof_ptr); + + unsigned char *input_rho_1 = reinterpret_cast(input_rho_ptr_1); + unsigned char *input_pk_1 = reinterpret_cast(input_pk_ptr_1); + unsigned char *authentication_path_1 = reinterpret_cast(input_authentication_path_ptr_1); + + unsigned char *input_rho_2 = reinterpret_cast(input_rho_ptr_2); + unsigned char *input_pk_2 = reinterpret_cast(input_pk_ptr_2); + unsigned char *authentication_path_2 = reinterpret_cast(input_authentication_path_ptr_2); + + unsigned char *output_rho_1 = reinterpret_cast(output_rho_ptr_1); + unsigned char *output_pk_1 = reinterpret_cast(output_pk_ptr_1); + unsigned char *output_rho_2 = reinterpret_cast(output_rho_ptr_2); + unsigned char *output_pk_2 = reinterpret_cast(output_pk_ptr_2); + + std::vector> auth_path_1; + for (int i = 0; i < 29; i++) { + auth_path_1.push_back(convertBytesVectorToVector(std::vector(authentication_path_1 + i*32, authentication_path_1 + i*32 + 32))); + } + + std::reverse(std::begin(auth_path_1), std::end(auth_path_1)); + + std::vector> auth_path_2; + for (int i = 0; i < 29; i++) { + auth_path_2.push_back(convertBytesVectorToVector(std::vector(authentication_path_2 + i*32, authentication_path_2 + i*32 + 32))); + } + + std::reverse(std::begin(auth_path_2), std::end(auth_path_2)); + + protoboard pb; + TransferCircuit g(pb); + g.generate_r1cs_constraints(); + g.generate_r1cs_witness( + std::vector(input_rho_1, input_rho_1 + 32), + std::vector(input_pk_1, input_pk_1 + 32), + input_value_1, + input_tree_position_1, + auth_path_1, + std::vector(input_rho_2, input_rho_2 + 32), + std::vector(input_pk_2, input_pk_2 + 32), + input_value_2, + input_tree_position_2, + auth_path_2, + std::vector(output_rho_1, output_rho_1 + 32), + std::vector(output_pk_1, output_pk_1 + 32), + output_value_1, + std::vector(output_rho_2, output_rho_2 + 32), + std::vector(output_pk_2, output_pk_2 + 32), + output_value_2 + ); + pb.constraint_system.swap_AB_if_beneficial(); + assert(pb.is_satisfied()); + + r1cs_ppzksnark_proving_key proving_key; + loadFromFile("transfer.pk", proving_key); + + auto proof = r1cs_ppzksnark_prover(proving_key, pb.primary_input(), pb.auxiliary_input(), pb.constraint_system); + + std::stringstream proof_data; + proof_data << proof; + auto proof_str = proof_data.str(); + assert(proof_str.size() == 584); + + for (int i = 0; i < 584; i++) { + output_proof[i] = proof_str[i]; + } +} + +void zsl_paramgen_transfer() +{ + protoboard pb; + TransferCircuit g(pb); + g.generate_r1cs_constraints(); + + const r1cs_constraint_system constraint_system = pb.get_constraint_system(); + cout << "Number of R1CS constraints: " << constraint_system.num_constraints() << endl; + auto crs = r1cs_ppzksnark_generator(constraint_system); + + saveToFile("transfer.pk", crs.pk); + saveToFile("transfer.vk", crs.vk); +} + +void zsl_paramgen_shielding() +{ + protoboard pb; + ShieldingCircuit g(pb); + g.generate_r1cs_constraints(); + + const r1cs_constraint_system constraint_system = pb.get_constraint_system(); + cout << "Number of R1CS constraints: " << constraint_system.num_constraints() << endl; + auto crs = r1cs_ppzksnark_generator(constraint_system); + + saveToFile("shielding.pk", crs.pk); + saveToFile("shielding.vk", crs.vk); +} + +void zsl_paramgen_unshielding() +{ + protoboard pb; + UnshieldingCircuit g(pb); + g.generate_r1cs_constraints(); + + const r1cs_constraint_system constraint_system = pb.get_constraint_system(); + cout << "Number of R1CS constraints: " << constraint_system.num_constraints() << endl; + auto crs = r1cs_ppzksnark_generator(constraint_system); + + saveToFile("unshielding.pk", crs.pk); + saveToFile("unshielding.vk", crs.vk); +} diff --git a/privacy/zsl/zsl/snark/libsnark/.gitignore b/privacy/zsl/zsl/snark/libsnark/.gitignore new file mode 100644 index 0000000..f6fb450 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/.gitignore @@ -0,0 +1,49 @@ +*.o +*.a +*.so +*.d +depinst/ +depsrc/ +README.html +doxygen/ +src/gadgetlib2/examples/tutorial +src/gadgetlib2/tests/gadgetlib2_test + +src/algebra/curves/tests/test_bilinearity +src/algebra/curves/tests/test_groups +src/algebra/fields/tests/test_fields +src/common/routing_algorithms/profiling/profile_routing_algorithms +src/common/routing_algorithms/tests/test_routing_algorithms +src/gadgetlib1/gadgets/cpu_checkers/fooram/examples/test_fooram +src/gadgetlib1/gadgets/hashes/knapsack/tests/test_knapsack_gadget +src/gadgetlib1/gadgets/hashes/sha256/tests/test_sha256_gadget +src/gadgetlib1/gadgets/merkle_tree/tests/test_merkle_tree_gadgets +src/gadgetlib1/gadgets/routing/profiling/profile_routing_gadgets +src/gadgetlib1/gadgets/set_commitment/tests/test_set_commitment_gadget +src/gadgetlib1/gadgets/verifiers/tests/test_r1cs_ppzksnark_verifier_gadget +src/reductions/ram_to_r1cs/examples/demo_arithmetization +src/relations/arithmetic_programs/qap/tests/test_qap +src/relations/arithmetic_programs/ssp/tests/test_ssp +src/zk_proof_systems/pcd/r1cs_pcd/r1cs_mp_ppzkpcd/profiling/profile_r1cs_mp_ppzkpcd +src/zk_proof_systems/pcd/r1cs_pcd/r1cs_mp_ppzkpcd/tests/test_r1cs_mp_ppzkpcd +src/zk_proof_systems/pcd/r1cs_pcd/r1cs_sp_ppzkpcd/profiling/profile_r1cs_sp_ppzkpcd +src/zk_proof_systems/pcd/r1cs_pcd/r1cs_sp_ppzkpcd/tests/test_r1cs_sp_ppzkpcd +src/zk_proof_systems/ppzkadsnark/r1cs_ppzkadsnark/examples/demo_r1cs_ppzkadsnark +src/zk_proof_systems/ppzksnark/bacs_ppzksnark/profiling/profile_bacs_ppzksnark +src/zk_proof_systems/ppzksnark/bacs_ppzksnark/tests/test_bacs_ppzksnark +src/zk_proof_systems/ppzksnark/r1cs_gg_ppzksnark/profiling/profile_r1cs_gg_ppzksnark +src/zk_proof_systems/ppzksnark/r1cs_gg_ppzksnark/tests/test_r1cs_gg_ppzksnark +src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/profiling/profile_r1cs_ppzksnark +src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/tests/test_r1cs_ppzksnark +src/zk_proof_systems/ppzksnark/ram_ppzksnark/examples/demo_ram_ppzksnark +src/zk_proof_systems/ppzksnark/ram_ppzksnark/examples/demo_ram_ppzksnark_generator +src/zk_proof_systems/ppzksnark/ram_ppzksnark/examples/demo_ram_ppzksnark_prover +src/zk_proof_systems/ppzksnark/ram_ppzksnark/examples/demo_ram_ppzksnark_verifier +src/zk_proof_systems/ppzksnark/ram_ppzksnark/profiling/profile_ram_ppzksnark +src/zk_proof_systems/ppzksnark/ram_ppzksnark/tests/test_ram_ppzksnark +src/zk_proof_systems/ppzksnark/tbcs_ppzksnark/profiling/profile_tbcs_ppzksnark +src/zk_proof_systems/ppzksnark/tbcs_ppzksnark/tests/test_tbcs_ppzksnark +src/zk_proof_systems/ppzksnark/uscs_ppzksnark/profiling/profile_uscs_ppzksnark +src/zk_proof_systems/ppzksnark/uscs_ppzksnark/tests/test_uscs_ppzksnark +src/zk_proof_systems/zksnark/ram_zksnark/profiling/profile_ram_zksnark +src/zk_proof_systems/zksnark/ram_zksnark/tests/test_ram_zksnark diff --git a/privacy/zsl/zsl/snark/libsnark/AUTHORS b/privacy/zsl/zsl/snark/libsnark/AUTHORS new file mode 100644 index 0000000..58f1401 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/AUTHORS @@ -0,0 +1,17 @@ +SCIPR Lab: + Eli Ben-Sasson + Alessandro Chiesa + Daniel Genkin + Shaul Kfir + Eran Tromer + Madars Virza + +External contributors: + Michael Backes + Manuel Barbosa + Dario Fiore + Jens Groth + Joshua A. Kroll + Shigeo MITSUNARI + Raphael Reischuk + Tadanori TERUYA diff --git a/privacy/zsl/zsl/snark/libsnark/LICENSE b/privacy/zsl/zsl/snark/libsnark/LICENSE new file mode 100644 index 0000000..81cea11 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/LICENSE @@ -0,0 +1,24 @@ +The libsnark library is developed by SCIPR Lab (http://scipr-lab.org) +and contributors. + +Copyright (c) 2012-2014 SCIPR Lab and contributors (see AUTHORS file). + +All files, with the exceptions below, are released under the MIT License: + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. diff --git a/privacy/zsl/zsl/snark/libsnark/Makefile b/privacy/zsl/zsl/snark/libsnark/Makefile new file mode 100644 index 0000000..6f166e2 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/Makefile @@ -0,0 +1,315 @@ +#******************************************************************************** +# Makefile for the libsnark library. +#******************************************************************************** +#* @author This file is part of libsnark, developed by SCIPR Lab +#* and contributors (see AUTHORS). +#* @copyright MIT license (see LICENSE file) +#*******************************************************************************/ + +# To override these, use "make OPTFLAGS=..." etc. +CURVE = BN128 +OPTFLAGS = -O2 -march=native -mtune=native +FEATUREFLAGS = -DUSE_ASM -DMONTGOMERY_OUTPUT + +# Initialize this using "CXXFLAGS=... make". The makefile appends to that. +CXXFLAGS += -std=c++11 -Wall -Wextra -Wno-unused-parameter -Wno-comment -Wfatal-errors $(OPTFLAGS) $(FEATUREFLAGS) -DCURVE_$(CURVE) + +DEPSRC = depsrc +DEPINST = depinst + +CXXFLAGS += -I$(DEPINST)/include -Isrc +LDFLAGS += -L$(DEPINST)/lib -Wl,-rpath,$(DEPINST)/lib +LDLIBS += -lgmpxx -lgmp -lboost_program_options +# OpenSSL and its dependencies (needed explicitly for static builds): +LDLIBS += -lcrypto -ldl -lz +# List of .a files to include within libsnark.a and libsnark.so: +AR_LIBS = +# List of library files to install: +INSTALL_LIBS = $(LIB_FILE) +# Sentinel file to check existence of this directory (since directories don't work as a Make dependency): +DEPINST_EXISTS = $(DEPINST)/.exists + + +COMPILE_GTEST := +ifneq ($(NO_GTEST),1) + GTESTDIR=/usr/src/gtest +# Compile GTest from sourcecode if we can (e.g., Ubuntu). Otherwise use precompiled one (e.g., Fedora). +# See https://code.google.com/p/googletest/wiki/FAQ#Why_is_it_not_recommended_to_install_a_pre-compiled_copy_of_Goog . + COMPILE_GTEST :=$(shell test -d $(GTESTDIR) && echo -n 1) + GTEST_LDLIBS += -lgtest -lpthread +endif + +ifneq ($(NO_SUPERCOP),1) + SUPERCOP_LDLIBS += -lsupercop + INSTALL_LIBS += depinst/lib/libsupercop.a + # Would have been nicer to roll supercop into libsnark.a ("AR_LIBS += $(DEPINST)/lib/libsupercop.a"), but it doesn't support position-independent code (libsnark issue #20). +endif + +LIB_SRCS = \ + src/algebra/curves/alt_bn128/alt_bn128_g1.cpp \ + src/algebra/curves/alt_bn128/alt_bn128_g2.cpp \ + src/algebra/curves/alt_bn128/alt_bn128_init.cpp \ + src/algebra/curves/alt_bn128/alt_bn128_pairing.cpp \ + src/algebra/curves/alt_bn128/alt_bn128_pp.cpp \ + src/algebra/curves/edwards/edwards_g1.cpp \ + src/algebra/curves/edwards/edwards_g2.cpp \ + src/algebra/curves/edwards/edwards_init.cpp \ + src/algebra/curves/edwards/edwards_pairing.cpp \ + src/algebra/curves/edwards/edwards_pp.cpp \ + src/algebra/curves/mnt/mnt4/mnt4_g1.cpp \ + src/algebra/curves/mnt/mnt4/mnt4_g2.cpp \ + src/algebra/curves/mnt/mnt4/mnt4_init.cpp \ + src/algebra/curves/mnt/mnt4/mnt4_pairing.cpp \ + src/algebra/curves/mnt/mnt4/mnt4_pp.cpp \ + src/algebra/curves/mnt/mnt46_common.cpp \ + src/algebra/curves/mnt/mnt6/mnt6_g1.cpp \ + src/algebra/curves/mnt/mnt6/mnt6_g2.cpp \ + src/algebra/curves/mnt/mnt6/mnt6_init.cpp \ + src/algebra/curves/mnt/mnt6/mnt6_pairing.cpp \ + src/algebra/curves/mnt/mnt6/mnt6_pp.cpp \ + src/common/data_structures/integer_permutation.cpp \ + src/common/data_structures/set_commitment.cpp \ + src/common/default_types/r1cs_ppzkpcd_pp.cpp \ + src/common/default_types/tinyram_ppzksnark_pp.cpp \ + src/common/default_types/r1cs_ppzkadsnark_pp.cpp \ + src/common/default_types/tinyram_zksnark_pp.cpp \ + src/common/profiling.cpp \ + src/common/routing_algorithms/as_waksman_routing_algorithm.cpp \ + src/common/routing_algorithms/benes_routing_algorithm.cpp \ + src/common/utils.cpp \ + src/gadgetlib1/constraint_profiling.cpp \ + src/gadgetlib2/adapters.cpp \ + src/gadgetlib2/constraint.cpp \ + src/gadgetlib2/examples/simple_example.cpp \ + src/gadgetlib2/gadget.cpp \ + src/gadgetlib2/infrastructure.cpp \ + src/gadgetlib2/integration.cpp \ + src/gadgetlib2/pp.cpp \ + src/gadgetlib2/protoboard.cpp \ + src/gadgetlib2/variable.cpp \ + src/relations/circuit_satisfaction_problems/tbcs/examples/tbcs_examples.cpp \ + src/relations/circuit_satisfaction_problems/tbcs/tbcs.cpp \ + src/relations/ram_computations/memory/examples/memory_contents_examples.cpp \ + src/relations/ram_computations/memory/memory_store_trace.cpp \ + src/relations/ram_computations/memory/ra_memory.cpp \ + src/relations/ram_computations/rams/fooram/fooram_aux.cpp \ + src/relations/ram_computations/rams/tinyram/tinyram_aux.cpp + +ifeq ($(CURVE),BN128) + LIB_SRCS += \ + src/algebra/curves/bn128/bn128_g1.cpp \ + src/algebra/curves/bn128/bn128_g2.cpp \ + src/algebra/curves/bn128/bn128_gt.cpp \ + src/algebra/curves/bn128/bn128_init.cpp \ + src/algebra/curves/bn128/bn128_pairing.cpp \ + src/algebra/curves/bn128/bn128_pp.cpp + + CXXFLAGS += -DBN_SUPPORT_SNARK + AR_LIBS += $(DEPINST)/lib/libzm.a +endif + +EXECUTABLES = \ + src/algebra/curves/tests/test_bilinearity \ + src/algebra/curves/tests/test_groups \ + src/algebra/fields/tests/test_fields \ + src/common/routing_algorithms/profiling/profile_routing_algorithms \ + src/common/routing_algorithms/tests/test_routing_algorithms \ + src/gadgetlib1/gadgets/cpu_checkers/fooram/examples/test_fooram \ + src/gadgetlib1/gadgets/hashes/knapsack/tests/test_knapsack_gadget \ + src/gadgetlib1/gadgets/hashes/sha256/tests/test_sha256_gadget \ + src/gadgetlib1/gadgets/merkle_tree/tests/test_merkle_tree_gadgets \ + src/gadgetlib1/gadgets/routing/profiling/profile_routing_gadgets \ + src/gadgetlib1/gadgets/set_commitment/tests/test_set_commitment_gadget \ + src/gadgetlib1/gadgets/verifiers/tests/test_r1cs_ppzksnark_verifier_gadget \ + src/reductions/ram_to_r1cs/examples/demo_arithmetization \ + src/relations/arithmetic_programs/qap/tests/test_qap \ + src/relations/arithmetic_programs/ssp/tests/test_ssp \ + src/zk_proof_systems/pcd/r1cs_pcd/r1cs_mp_ppzkpcd/profiling/profile_r1cs_mp_ppzkpcd \ + src/zk_proof_systems/pcd/r1cs_pcd/r1cs_mp_ppzkpcd/tests/test_r1cs_mp_ppzkpcd \ + src/zk_proof_systems/pcd/r1cs_pcd/r1cs_sp_ppzkpcd/profiling/profile_r1cs_sp_ppzkpcd \ + src/zk_proof_systems/pcd/r1cs_pcd/r1cs_sp_ppzkpcd/tests/test_r1cs_sp_ppzkpcd \ + src/zk_proof_systems/ppzksnark/bacs_ppzksnark/profiling/profile_bacs_ppzksnark \ + src/zk_proof_systems/ppzksnark/bacs_ppzksnark/tests/test_bacs_ppzksnark \ + src/zk_proof_systems/ppzksnark/r1cs_gg_ppzksnark/profiling/profile_r1cs_gg_ppzksnark \ + src/zk_proof_systems/ppzksnark/r1cs_gg_ppzksnark/tests/test_r1cs_gg_ppzksnark \ + src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/profiling/profile_r1cs_ppzksnark \ + src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/tests/test_r1cs_ppzksnark \ + src/zk_proof_systems/ppzksnark/ram_ppzksnark/examples/demo_ram_ppzksnark \ + src/zk_proof_systems/ppzksnark/ram_ppzksnark/examples/demo_ram_ppzksnark_generator \ + src/zk_proof_systems/ppzksnark/ram_ppzksnark/examples/demo_ram_ppzksnark_prover \ + src/zk_proof_systems/ppzksnark/ram_ppzksnark/examples/demo_ram_ppzksnark_verifier \ + src/zk_proof_systems/ppzksnark/ram_ppzksnark/profiling/profile_ram_ppzksnark \ + src/zk_proof_systems/ppzksnark/ram_ppzksnark/tests/test_ram_ppzksnark \ + src/zk_proof_systems/ppzksnark/tbcs_ppzksnark/profiling/profile_tbcs_ppzksnark \ + src/zk_proof_systems/ppzksnark/tbcs_ppzksnark/tests/test_tbcs_ppzksnark \ + src/zk_proof_systems/ppzksnark/uscs_ppzksnark/profiling/profile_uscs_ppzksnark \ + src/zk_proof_systems/ppzksnark/uscs_ppzksnark/tests/test_uscs_ppzksnark \ + src/zk_proof_systems/zksnark/ram_zksnark/profiling/profile_ram_zksnark \ + src/zk_proof_systems/zksnark/ram_zksnark/tests/test_ram_zksnark + + +EXECUTABLES_WITH_GTEST = \ + src/gadgetlib1/tests/gadgetlib1_test \ + src/gadgetlib2/examples/tutorial \ + src/gadgetlib2/tests/gadgetlib2_test + +EXECUTABLES_WITH_SUPERCOP = \ + src/zk_proof_systems/ppzkadsnark/r1cs_ppzkadsnark/examples/demo_r1cs_ppzkadsnark + +DOCS = README.html + +LIBSNARK_A = libsnark.a + +# For documentation of the following options, see README.md . + +ifeq ($(NO_PROCPS),1) + CXXFLAGS += -DNO_PROCPS +else + LDLIBS += -lprocps +endif + +ifeq ($(LOWMEM),1) + CXXFLAGS += -DLOWMEM +endif + +ifeq ($(PROFILE_OP_COUNTS),1) + STATIC = 1 + CXXFLAGS += -DPROFILE_OP_COUNTS +endif + +ifeq ($(STATIC),1) + CXXFLAGS += -static -DSTATIC +else + CXXFLAGS += -fPIC +endif + +ifeq ($(MULTICORE),1) + CXXFLAGS += -DMULTICORE -fopenmp +endif + +ifeq ($(CPPDEBUG),1) + CXXFLAGS += -D_GLIBCXX_DEBUG -D_GLIBCXX_DEBUG_PEDANTIC + DEBUG = 1 +endif + +ifeq ($(DEBUG),1) + CXXFLAGS += -DDEBUG -ggdb3 +endif + +ifeq ($(PERFORMANCE),1) + OPTFLAGS = -O3 -march=native -mtune=native + CXXFLAGS += -DNDEBUG + # Enable link-time optimization: + CXXFLAGS += -flto -fuse-linker-plugin + LDFLAGS += -flto +endif + +LIB_OBJS =$(patsubst %.cpp,%.o,$(LIB_SRCS)) +EXEC_OBJS =$(patsubst %,%.o,$(EXECUTABLES) $(EXECUTABLES_WITH_GTEST) $(EXECUTABLES_WITH_SUPERCOP)) + +all: \ + $(if $(NO_GTEST),,$(EXECUTABLES_WITH_GTEST)) \ + $(if $(NO_SUPERCOP),,$(EXECUTABLES_WITH_SUPERCOP)) \ + $(EXECUTABLES) \ + $(if $(NO_DOCS),,doc) + +doc: $(DOCS) + +$(DEPINST_EXISTS): + # Create placeholder directories for installed dependencies. Some make settings (including the default) require actually running ./prepare-depends.sh to populate this directory. + mkdir -p $(DEPINST)/lib $(DEPINST)/include + touch $@ + +# In order to detect changes to #include dependencies. -MMD below generates a .d file for each .o file. Include the .d file. +-include $(patsubst %.o,%.d, $(LIB_OBJS) $(EXEC_OBJS) ) + +$(LIB_OBJS) $(EXEC_OBJS): %.o: %.cpp + $(CXX) -o $@ $< -c -MMD $(CXXFLAGS) + +LIBGTEST_A = $(DEPINST)/lib/libgtest.a + +$(LIBGTEST_A): $(GTESTDIR)/src/gtest-all.cc $(DEPINST_EXISTS) + $(CXX) -o $(DEPINST)/lib/gtest-all.o -I $(GTESTDIR) -c -isystem $(GTESTDIR)/include $< $(CXXFLAGS) + $(AR) -rv $(LIBGTEST_A) $(DEPINST)/lib/gtest-all.o + +# libsnark.a will contains all of our relevant object files, and we also mash in the .a files of relevant dependencies built by ./prepare-depends.sh +$(LIBSNARK_A): $(LIB_OBJS) $(AR_LIBS) + ( \ + echo "create $(LIBSNARK_A)"; \ + echo "addmod $(LIB_OBJS)"; \ + if [ -n "$(AR_LIBS)" ]; then for AR_LIB in $(AR_LIBS); do echo addlib $$AR_LIB; done; fi; \ + echo "save"; \ + echo "end"; \ + ) | $(AR) -M + $(AR) s $(LIBSNARK_A) + +libsnark.so: $(LIBSNARK_A) $(DEPINST_EXISTS) + $(CXX) -o $@ --shared -Wl,--whole-archive $(LIBSNARK_A) $(CXXFLAGS) $(LDFLAGS) -Wl,--no-whole-archive $(LDLIBS) + +src/gadgetlib2/tests/gadgetlib2_test: \ + src/gadgetlib2/tests/adapters_UTEST.cpp \ + src/gadgetlib2/tests/constraint_UTEST.cpp \ + src/gadgetlib2/tests/gadget_UTEST.cpp \ + src/gadgetlib2/tests/integration_UTEST.cpp \ + src/gadgetlib2/tests/protoboard_UTEST.cpp \ + src/gadgetlib2/tests/variable_UTEST.cpp + +$(EXECUTABLES): %: %.o $(LIBSNARK_A) $(DEPINST_EXISTS) + $(CXX) -o $@ $@.o $(LIBSNARK_A) $(CXXFLAGS) $(LDFLAGS) $(LDLIBS) + +$(EXECUTABLES_WITH_GTEST): %: %.o $(LIBSNARK_A) $(if $(COMPILE_GTEST),$(LIBGTEST_A)) $(DEPINST_EXISTS) + $(CXX) -o $@ $@.o $(LIBSNARK_A) $(CXXFLAGS) $(LDFLAGS) $(GTEST_LDLIBS) $(LDLIBS) + +$(EXECUTABLES_WITH_SUPERCOP): %: %.o $(LIBSNARK_A) $(DEPINST_EXISTS) + $(CXX) -o $@ $@.o $(LIBSNARK_A) $(CXXFLAGS) $(LDFLAGS) $(SUPERCOP_LDLIBS) $(LDLIBS) + + +ifeq ($(STATIC),1) +LIB_FILE = $(LIBSNARK_A) +else +LIB_FILE = libsnark.so +endif + +lib: $(LIB_FILE) + +$(DOCS): %.html: %.md + markdown_py -f $@ $^ -x toc -x extra --noisy +# TODO: Would be nice to enable "-x smartypants" but Ubuntu 12.04 doesn't support that. +# TODO: switch to redcarpet, to produce same output as GitHub's processing of README.md. But what about TOC? + +ifeq ($(PREFIX),) +install: + $(error Please provide PREFIX. E.g. make install PREFIX=/usr) +else +HEADERS_SRC=$(shell find src -name '*.hpp' -o -name '*.tcc') +HEADERS_DEST=$(patsubst src/%,$(PREFIX)/include/libsnark/%,$(HEADERS_SRC)) + +$(HEADERS_DEST): $(PREFIX)/include/libsnark/%: src/% + mkdir -p $(shell dirname $@) + cp $< $@ + +install: $(INSTALL_LIBS) $(HEADERS_DEST) $(DEPINST_EXISTS) + mkdir -p $(PREFIX)/lib + cp -v $(INSTALL_LIBS) $(PREFIX)/lib/ + cp -rv $(DEPINST)/include $(PREFIX) +endif + +doxy: + doxygen doxygen.conf + +# Clean generated files, except locally-compiled dependencies +clean: + $(RM) \ + $(LIB_OBJS) $(EXEC_OBJS) \ + $(EXECUTABLES) $(EXECUTABLES_WITH_GTEST) $(EXECUTABLES_WITH_SUPERCOP) \ + $(DOCS) \ + ${patsubst %.o,%.d,${LIB_OBJS} ${EXEC_OBJS}} \ + libsnark.so $(LIBSNARK_A) \ + $(RM) -fr doxygen/ \ + $(RM) $(LIBGTEST_A) $(DEPINST)/lib/gtest-all.o + +# Clean all, including locally-compiled dependencies +clean-all: clean + $(RM) -fr $(DEPSRC) $(DEPINST) + +.PHONY: all clean clean-all doc doxy lib install diff --git a/privacy/zsl/zsl/snark/libsnark/README.md b/privacy/zsl/zsl/snark/libsnark/README.md new file mode 100644 index 0000000..19f763a --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/README.md @@ -0,0 +1,629 @@ +libsnark: a C++ library for zkSNARK proofs +================================================================================ + +-------------------------------------------------------------------------------- +Authors +-------------------------------------------------------------------------------- + +The libsnark library is developed by the [SCIPR Lab] project and contributors +and is released under the MIT License (see the [LICENSE] file). + +Copyright (c) 2012-2014 SCIPR Lab and contributors (see [AUTHORS] file). + +-------------------------------------------------------------------------------- +[TOC] + + + +-------------------------------------------------------------------------------- +Overview +-------------------------------------------------------------------------------- + +This library implements __zkSNARK__ schemes, which are a cryptographic method +for proving/verifying, in zero knowledge, the integrity of computations. + +A computation can be expressed as an NP statement, in forms such as the following: + +- "The C program _foo_, when executed, returns exit code 0 if given the input _bar_ and some additional input _qux_." +- "The Boolean circuit _foo_ is satisfiable by some input _qux_." +- "The arithmetic circuit _foo_ accepts the partial assignment _bar_, when extended into some full assignment _qux_." +- "The set of constraints _foo_ is satisfiable by the partial assignment _bar_, when extended into some full assignment _qux_." + +A prover who knows the witness for the NP statement (i.e., a satisfying input/assignment) can produce a short proof attesting to the truth of the NP statement. This proof can be verified by anyone, and offers the following properties. + +- __Zero knowledge:__ + the verifier learns nothing from the proof beside the truth of the statement (i.e., the value _qux_, in the above examples, remains secret). +- __Succinctness:__ + the proof is short and easy to verify. +- __Non-interactivity:__ + the proof is a string (i.e. it does not require back-and-forth interaction between the prover and the verifier). +- __Soundness:__ + the proof is computationally sound (i.e., it is infeasible to fake a proof of a false NP statement). Such a proof system is also called an _argument_. +- __Proof of knowledge:__ + the proof attests not just that the NP statement is true, but also that the + prover knows why (e.g., knows a valid _qux_). + +These properties are summarized by the _zkSNARK_ acronym, which stands for _Zero-Knowledge Succinct Non-interactive ARgument of Knowledge_ (though zkSNARKs are also knows as +_succinct non-interactive computationally-sound zero-knowledge proofs of knowledge_). +For formal definitions and theoretical discussions about these, see +\[BCCT12], \[BCIOP13], and the references therein. + +The libsnark library currently provides a C++ implementation of: + +1. General-purpose proof systems: + 1. A preprocessing zkSNARK for the NP-complete language "R1CS" + (_Rank-1 Constraint Systems_), which is a language that is similar to arithmetic + circuit satisfiability. + + This zkSNARK construction follows, extends, and + optimizes the approach described in \[BCTV14a], itself an extension of + \[BCGTV13], following the approach of \[GGPR13] and \[BCIOP13]. (An alternative + implementation of this approach is the _Pinocchio_ system of \[PGHR13].) + 2. A preprocessing SNARK for a language of arithmetic circuits, "BACS" + (_Bilinear Arithmetic Circuit Satisfiability_). This simplifies the writing + of NP statements when the additional flexibility of R1CS is not needed. + Internally, it reduces to R1CS. + 3. A preprocessing SNARK for the language "USCS" + (_Unitary-Square Constraint Systems_). This abstracts and implements the core + contribution of \[DFGK14] + 4. A preprocessing SNARK for a language of Boolean circuits, "TBCS" + (_Two-input Boolean Circuit Satisfiability_). Internally, it reduces to USCS. + This is much more efficient than going through R1CS. + 5. ADSNARK, a preprocessing SNARKs for proving statements on authenticated + data, as described in \[BBFR15]. + 6. Proof-Carrying Data (PCD). This uses recursive composition of SNARKs, as + explained in \[BCCT13] and optimized in \[BCTV14b]. +2. Gadget libraries (gadgetlib1 and gadgetlib2) for constructing R1CS + instances out of modular "gadget" classes. +3. Examples of applications that use the above proof systems to prove + statements about: + 1. Several toy examples. + 2. Execution of TinyRAM machine code, as explained in \[BCTV14a] and + \[BCGTV13]. (Such machine code can be obtained, e.g., by compiling from C.) + This is easily adapted to any other Random Access Machine that satisfies a + simple load-store interface. + 3. A scalable for TinyRAM using Proof-Carrying Data, as explained in \[BCTV14b] + 4. Zero-knowldge cluster MapReduce, as explained in \[CTV15]. + +See the above references for discussions of efficiency aspects that arise in +practical use of such constructions, as well as security and trust +considerations. + +This scheme is a _preprocessing zkSNARK_ (_ppzkSNARK_): before proofs can be +created and verified, one needs to first decide on a size/circuit/system +representing the NP statements to be proved, and run a _generator_ algorithm to +create corresponding public parameters (a long proving key and a short +verification key). + +Using the library involves the following high-level steps: + +1. Express the statements to be proved as an R1CS (or any of the other + languages above, such as arithmetic circuits, Boolean circuits, or TinyRAM). + This is done by writing C++ code that constructs an R1CS, and linking this code + together with libsnark +2. Use libsnark's generator algorithm to create the public parameters for this + statement (once and for all). +3. Use libsnark's prover algorithm to create proofs of true statements about + the satisfiability of the R1CS. +4. Use libsnark's verifier algorithm to check proofs for alleged statements. + + +-------------------------------------------------------------------------------- +The NP-complete language R1CS +-------------------------------------------------------------------------------- + +The ppzkSNARK supports proving/verifying membership in a specific NP-complete +language: R1CS (*rank-1 constraint systems*). An instance of the language is +specified by a set of equations over a prime field F, and each equation looks like: + < A, (1,X) > * < B , (1,X) > = < C, (1,X) > +where A,B,C are vectors over F, and X is a vector of variables. + +In particular, arithmetic (as well as boolean) circuits are easily reducible to +this language by converting each gate into a rank-1 constraint. See \[BCGTV13] +Appendix E (and "System of Rank 1 Quadratic Equations") for more details about this. + + +-------------------------------------------------------------------------------- +Elliptic curve choices +-------------------------------------------------------------------------------- + +The ppzkSNARK can be instantiated with different parameter choices, depending on +which elliptic curve is used. The libsnark library currently provides three +options: + +* "edwards": + an instantiation based on an Edwards curve, providing 80 bits of security. + +* "bn128": + an instantiation based on a Barreto-Naehrig curve, providing 128 + bits of security. The underlying curve implementation is + \[ate-pairing], which has incorporated our patch that changes the + BN curve to one suitable for SNARK applications. + + * This implementation uses dynamically-generated machine code for the curve + arithmetic. Some modern systems disallow execution of code on the heap, and + will thus block this implementation. + + For example, on Fedora 20 at its default settings, you will get the error + `zmInit ERR:can't protect` when running this code. To solve this, + run `sudo setsebool -P allow_execheap 1` to allow execution, + or use `make CURVE=ALT_BN128` instead. + +* "alt_bn128": + an alternative to "bn128", somewhat slower but avoids dynamic code generation. + +Note that bn128 requires an x86-64 CPU while the other curve choices +should be architecture-independent; see [portability](#portability). + + +-------------------------------------------------------------------------------- +Gadget libraries +-------------------------------------------------------------------------------- + +The libsnark library currently provides two libraries for conveniently constructing +R1CS instances out of reusable "gadgets". Both libraries provide a way to construct +gadgets on other gadgets as well as additional explicit equations. In this way, +complex R1CS instances can be built bottom up. + +### gadgetlib1 + +This is a low-level library which expose all features of the preprocessing +zkSNARK for R1CS. Its design is based on templates (as does the ppzkSNARK code) +to efficiently support working on multiple elliptic curves simultaneously. This +library is used for most of the constraint-building in libsnark, both internal +(reductions and Proof-Carrying Data) and examples applications. + +### gadgetlib2 + +This is an alternative library for constructing systems of polynomial equations +and, in particular, also R1CS instances. It is better documented and easier to +use than gadgetlib1, and its interface does not use templates. However, fewer +useful gadgets are provided. + + +-------------------------------------------------------------------------------- +Security +-------------------------------------------------------------------------------- + +The theoretical security of the underlying mathematical constructions, and the +requisite assumptions, are analyzed in detailed in the aforementioned research +papers. + +** +This code is a research-quality proof of concept, and has not +yet undergone extensive review or testing. It is thus not suitable, +as is, for use in critical or production systems. +** + +Known issues include the following: + +* The ppzkSNARK's generator and prover exhibit data-dependent running times + and memory usage. These form timing and cache-contention side channels, + which may be an issue in some applications. + +* Randomness is retrieved from /dev/urandom, but this should be + changed to a carefully considered (depending on system and threat + model) external, high-quality randomness source when creating + long-term proving/verification keys. + + +-------------------------------------------------------------------------------- +Build instructions +-------------------------------------------------------------------------------- + +The libsnark library relies on the following: + +- C++ build environment +- GMP for certain bit-integer arithmetic +- libprocps for reporting memory usage +- GTest for some of the unit tests + +So far we have tested these only on Linux, though we have been able to make the library work, +with some features disabled (such as memory profiling or GTest tests), on Windows via Cygwin +and on Mac OS X. (If you succeed in achieving more complete ports of the library, please +let us know!) See also the notes on [portability](#portability) below. + +For example, on a fresh install of Ubuntu 14.04, install the following packages: + + $ sudo apt-get install build-essential git libgmp3-dev libprocps3-dev libgtest-dev python-markdown libboost-all-dev libssl-dev + +Or, on Fedora 20: + + $ sudo yum install gcc-c++ make git gmp-devel procps-ng-devel gtest-devel python-markdown + +Run the following, to fetch dependencies from their GitHub repos and compile them. +(Not required if you set `CURVE` to other than the default `BN128` and also set `NO_SUPERCOP=1`.) + + $ ./prepare-depends.sh + +Then, to compile the library, tests, profiling harness and documentation, run: + + $ make + +To create just the HTML documentation, run + + $ make doc + +and then view the resulting `README.html` (which contains the very text you are reading now). + +To create Doxygen documentation summarizing all files, classes and functions, +with some (currently sparse) comments, install the `doxygen` and `graphviz` packages, then run + + $ make doxy + +(this may take a few minutes). Then view the resulting [`doxygen/index.html`](doxygen/index.html). + +### Using libsnark as a library + +To develop an application that uses libsnark, you could add it within the libsnark directory tree and adjust the Makefile, but it is far better to build libsnark as a (shared or static) library. You can then write your code in a separate directory tree, and link it against libsnark. + + +To build just the shared object library `libsnark.so`, run: + + $ make lib + +To build just the static library `libsnark.a`, run: + + $ make lib STATIC=1 + +Note that static compilation requires static versions of all libraries it depends on. +It may help to minize these dependencies by appending +`CURVE=ALT_BN128 NO_PROCPS=1 NO_GTEST=1 NO_SUPERCOP=1`. On Fedora 21, the requisite +library RPM dependencies are then: +`boost-static glibc-static gmp-static libstdc++-static openssl-static zlib-static + boost-devel glibc-devel gmp-devel gmp-devel libstdc++-devel openssl-devel openssl-devel`. + +To build *and install* the libsnark library: + + $ make install PREFIX=/install/path + +This will install `libsnark.so` into `/install/path/lib`; so your application should be linked using `-L/install/path/lib -lsnark`. It also installs the requisite headers into `/install/path/include`; so your application should be compiled using `-I/install/path/include`. + +In addition, unless you use `NO_SUPERCOP=1`, `libsupercop.a` will be installed and should be linked in using `-lsupercop`. + + +### Building on Windows using Cygwin +Install Cygwin using the graphical installer, including the `g++`, `libgmp` +and `git` packages. Then disable the dependencies not easily supported under CygWin, +using: + + $ make NO_PROCPS=1 NO_GTEST=1 NO_DOCS=1 + + +### Building on Mac OS X + +On Mac OS X, install GMP from MacPorts (`port install gmp`). Then disable the +dependencies not easily supported under CygWin, using: + + $ make NO_PROCPS=1 NO_GTEST=1 NO_DOCS=1 + +MacPorts does not write its libraries into standard system folders, so you +might need to explicitly provide the paths to the header files and libraries by +appending `CXXFLAGS=-I/opt/local/include LDFLAGS=-L/opt/local/lib` to the line +above. Similarly, to pass the paths to ate-pairing you would run +`INC_DIR=-I/opt/local/include LIB_DIR=-L/opt/local/lib ./prepare-depends.sh` +instead of `./prepare-depends.sh` above. + +-------------------------------------------------------------------------------- +Tutorials +-------------------------------------------------------------------------------- + +libsnark includes a tutorial, and some usage examples, for the high-level API. + +* `src/gadgetlib1/examples1` contains a simple example for constructing a + constraint system using gadgetlib1. + +* `src/gadgetlib2/examples` contains a tutorial for using gadgetlib2 to express + NP statements as constraint systems. It introduces basic terminology, design + overview, and recommended programming style. It also shows how to invoke + ppzkSNARKs on such constraint systems. The main file, `tutorial.cpp`, builds + into a standalone executable. + +* `src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/profiling/profile_r1cs_ppzksnark.cpp` + constructs a simple constraint system and runs the ppzksnark. See below for how to + run it. + + +-------------------------------------------------------------------------------- +Executing profiling example +-------------------------------------------------------------------------------- + +The command + + $ src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/profiling/profile_r1cs_ppzksnark 1000 10 Fr + +exercises the ppzkSNARK (first generator, then prover, then verifier) on an +R1CS instance with 1000 equations and an input consisting of 10 field elements. + +(If you get the error `zmInit ERR:can't protect`, see the discussion +[above](#elliptic-curve-choices).) + +The command + + $ src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/profiling/profile_r1cs_ppzksnark 1000 10 bytes + +does the same but now the input consists of 10 bytes. + + +-------------------------------------------------------------------------------- +Build options +-------------------------------------------------------------------------------- + +The following flags change the behavior of the compiled code. + +* `make FEATUREFLAGS='-Dname1 -Dname2 ...'` + + Override the active conditional #define names (you can see the default at the top of the Makefile). + The next bullets list the most important conditionally-#defined features. + For example, `make FEATUREFLAGS='-DBINARY_OUTPUT'` enables binary output and disables the default + assembly optimizations and Montgomery-representation output. + +* define `BINARY_OUTPUT` + + In serialization, output raw binary data (instead of decimal, when not set). + +* `make CURVE=choice` / define `CURVE_choice` (where `choice` is one of: + ALT_BN128, BN128, EDWARDS, MNT4, MNT6) + + Set the default curve to one of the above (see [elliptic curve choices](#elliptic-curve-choices)). + +* `make DEBUG=1` / define `DEBUG` + + Print additional information for debugging purposes. + +* `make LOWMEM=1` / define `LOWMEM` + + Limit the size of multi-exponentiation tables, for low-memory platforms. + +* `make NO_DOCS=1` + + Do not generate HTML documentation, e.g. on platforms where Markdown is not easily available. + +* `make NO_PROCPS=1` + + Do not link against libprocps. This disables memory profiling. + +* `make NO_GTEST=1` + + Do not link against GTest. The tutorial and test suite of gadgetlib2 tutorial won't be compiled. + +* `make NO_SUPERCOP=1` + + Do not link against SUPERCOP for optimized crypto. The ADSNARK executables will not be built. + +* `make MULTICORE=1` + + Enable parallelized execution of the ppzkSNARK generator and prover, using OpenMP. + This will utilize all cores on the CPU for heavyweight parallelizabe operations such as + FFT and multiexponentiation. The default is single-core. + + To override the maximum number of cores used, set the environment variable `OMP_NUM_THREADS` + at runtime (not compile time), e.g., `OMP_NUM_THREADS=8 test_r1cs_sp_ppzkpc`. It defaults + to the autodetected number of cores, but on some devices, dynamic core management confused + OpenMP's autodetection, so setting `OMP_NUM_THREADS` is necessary for full utilization. + +* define `NO_PT_COMPRESSION` + + Do not use point compression. + This gives much faster serialization times, at the expense of ~2x larger + sizes for serialized keys and proofs. + +* define `MONTGOMERY_OUTPUT` (on by default) + + Serialize Fp elements as their Montgomery representations. If this + option is disabled then Fp elements are serialized as their + equivalence classes, which is slower but produces human-readable + output. + +* `make PROFILE_OP_COUNTS=1` / define `PROFILE_OP_COUNTS` + + Collect counts for field and curve operations inside static variables + of the corresponding algebraic objects. This option works for all + curves except bn128. + +* define `USE_ASM` (on by default) + + Use unrolled assembly routines for F[p] arithmetic and faster heap in + multi-exponentiation. (When not set, use GMP's `mpn_*` routines instead.) + +* define `USE_MIXED_ADDITION` + + Convert each element of the proving key and verification key to + affine coordinates. This allows using mixed addition formulas in + multiexponentiation and results in slightly faster prover and + verifier runtime at expense of increased proving time. + +* `make PERFORMANCE=1` + + Enables compiler optimizations such as link-time optimization, and disables debugging aids. + (On some distributions this causes a `plugin needed to handle lto object` link error and `undefined reference`s, which can be remedied by `AR=gcc-ar make ...`.) + +Not all combinations are tested together or supported by every part of the codebase. + + +-------------------------------------------------------------------------------- +Portability +-------------------------------------------------------------------------------- + +libsnark is written in fairly standard C++11. + +However, having been developed on Linux on x86-64 CPUs, libsnark has some limitations +with respect to portability. Specifically: + +1. libsnark's algebraic data structures assume little-endian byte order. + +2. Profiling routines use `clock_gettime` and `readproc` calls, which are Linux-specific. + +3. Random-number generation is done by reading from `/dev/urandom`, which is + specific to Unix-like systems. + +4. libsnark binary serialization routines (see `BINARY_OUTPUT` above) assume + a fixed machine word size (i.e. sizeof(mp_limb_t) for GMP's limb data type). + Objects serialized in binary on a 64-bit system cannot be de-serialized on + a 32-bit system, and vice versa. + (The decimal serialization routines have no such limitation.) + +5. libsnark requires a C++ compiler with good C++11 support. It has been + tested with g++ 4.7, g++ 4.8, and clang 3.4. + +6. On x86-64, we by default use highly optimized assembly implementations for some + operations (see `USE_ASM` above). On other architectures we fall back to a + portable C++ implementation, which is slower. + +Tested configurations include: + +* Debian jessie with g++ 4.7 on x86-64 +* Debian jessie with clang 3.4 on x86-64 +* Fedora 20/21 with g++ 4.8.2/4.9.2 on x86-64 and i686 +* Ubuntu 14.04 LTS with g++ 4.8 on x86-64 +* Ubuntu 14.04 LTS with g++ 4.8 on x86-32, for EDWARDS and ALT_BN128 curve choices +* Debian wheezy with g++ 4.7 on ARM little endian (Debian armel port) inside QEMU, for EDWARDS and ALT_BN128 curve choices +* Windows 7 with g++ 4.8.3 under Cygwin 1.7.30 on x86-64 with NO_PROCPS=1, NO_GTEST=1 and NO_DOCS=1, for EDWARDS and ALT_BN128 curve choices +* Mac OS X 10.9.4 (Mavericks) with Apple LLVM version 5.1 (based on LLVM 3.4svn) on x86-64 with NO_PROCPS=1, NO_GTEST=1 and NO_DOCS=1 + + +-------------------------------------------------------------------------------- +Directory structure +-------------------------------------------------------------------------------- + +The directory structure of the libsnark library is as follows: + +* src/ --- main C++ source code, containing the following modules: + * algebra/ --- fields and elliptic curve groups + * common/ --- miscellaneous utilities + * gadgetlib1/ --- gadgetlib1, a library to construct R1CS instances + * gadgets/ --- basic gadgets for gadgetlib1 + * gadgetlib2/ --- gadgetlib2, a library to construct R1CS instances + * qap/ --- quadratic arithmetic program + * domains/ --- support for fast interpolation/evaluation, by providing + FFTs and Lagrange-coefficient computations for various domains + * relations/ --- interfaces for expressing statement (relations between instances and witnesses) as various NP-complete languages + * constraint_satisfaction_problems/ --- R1CS and USCS languages + * circuit_satisfaction_problems/ --- Boolean and arithmetic circuit satisfiability languages + * ram_computations/ --- RAM computation languages + * zk_proof_systems --- interfaces and implementations of the proof systems + * reductions --- reductions between languages (used internally, but contains many examples of building constraints) + + Some of these module directories have the following subdirectories: + + * ... + * examples/ --- example code and tutorials for this module + * tests/ --- unit tests for this module + + In particular, the top-level API examples are at `src/r1cs_ppzksnark/examples/` and `src/gadgetlib2/examples/`. + +* depsrc/ --- created by `prepare_depends.sh` for retrieved sourcecode and local builds of external code + (currently: \[ate-pairing], and its dependency xbyak). + +* depinst/ --- created by `prepare_depends.sh` and `Makefile` + for local installation of locally-compiled dependencies. + +* doxygen/ --- created by `make doxy` and contains a Doxygen summary of all files, classes etc. in libsnark. + + +-------------------------------------------------------------------------------- +Further considerations +-------------------------------------------------------------------------------- + +### Multiexponentiation window size + +The ppzkSNARK's generator has to solve a fixed-base multi-exponentiation +problem. We use a window-based method in which the optimal window size depends +on the size of the multiexponentiation instance *and* the platform. + +On our benchmarking platform (a 3.40 GHz Intel Core i7-4770 CPU), we have +computed for each curve optimal windows, provided as +"fixed_base_exp_window_table" initialization sequences, for each curve; see +`X_init.cpp` for X=edwards,bn128,alt_bn128. + +Performance on other platforms may not be optimal (but probably not be far off). +Future releases of the libsnark library will include a tool that generates +optimal window sizes. + + +-------------------------------------------------------------------------------- +References +-------------------------------------------------------------------------------- + +\[BBFR15] [ + _ADSNARK: nearly practical and privacy-preserving proofs on authenticated data_ +](https://eprint.iacr.org/2014/617), + Michael Backes, Manuel Barbosa, Dario Fiore, Raphael M. Reischuk, + IEEE Symposium on Security and Privacy (Oakland) 2015 + +\[BCCT12] [ + _From extractable collision resistance to succinct non-Interactive arguments of knowledge, and back again_ +](http://eprint.iacr.org/2011/443), + Nir Bitansky, Ran Canetti, Alessandro Chiesa, Eran Tromer, + Innovations in Computer Science (ITCS) 2012 + +\[BCCT13] [ + _Recursive composition and bootstrapping for SNARKs and proof-carrying data_ +](http://eprint.iacr.org/2012/095) + Nir Bitansky, Ran Canetti, Alessandro Chiesa, Eran Tromer, + Symposium on Theory of Computing (STOC) 13 + +\[BCGTV13] [ + _SNARKs for C: Verifying Program Executions Succinctly and in Zero Knowledge_ +](http://eprint.iacr.org/2013/507), + Eli Ben-Sasson, Alessandro Chiesa, Daniel Genkin, Eran Tromer, Madars Virza, + CRYPTO 2013 + +\[BCIOP13] [ + _Succinct non-interactive arguments via linear interactive Proofs_ +](http://eprint.iacr.org/2012/718), + Nir Bitansky, Alessandro Chiesa, Yuval Ishai, Rafail Ostrovsky, Omer Paneth, + Theory of Cryptography Conference 2013 + +\[BCTV14a] [ + _Succinct non-interactive zero knowledge for a von Neumann architecture_ +](http://eprint.iacr.org/2013/879), + Eli Ben-Sasson, Alessandro Chiesa, Eran Tromer, Madars Virza, + USENIX Security 2014 + +\[BCTV14b] [ + _Scalable succinct non-interactive arguments via cycles of elliptic curves_ +](https://eprint.iacr.org/2014/595), + Eli Ben-Sasson, Alessandro Chiesa, Eran Tromer, Madars Virza, + CRYPTO 2014 + +\[CTV15] [ + _Cluster computing in zero knowledge_ +](https://eprint.iacr.org/2015/377), + Alessandro Chiesa, Eran Tromer, Madars Virza, + Eurocrypt 2015 + +\[DFGK14] [ + Square span programs with applications to succinct NIZK arguments +](https://eprint.iacr.org/2014/718), + George Danezis, Cedric Fournet, Jens Groth, Markulf Kohlweiss, + ASIACCS 2014 + +\[GGPR13] [ + _Quadratic span programs and succinct NIZKs without PCPs_ +](http://eprint.iacr.org/2012/215), + Rosario Gennaro, Craig Gentry, Bryan Parno, Mariana Raykova, + EUROCRYPT 2013 + +\[ate-pairing] [ + _High-Speed Software Implementation of the Optimal Ate Pairing over Barreto-Naehrig Curves_ +](https://github.com/herumi/ate-pairing), + MITSUNARI Shigeo, TERUYA Tadanori + +\[PGHR13] [ + _Pinocchio: Nearly Practical Verifiable Computation_ +](http://eprint.iacr.org/2013/279), + Bryan Parno, Craig Gentry, Jon Howell, Mariana Raykova, + IEEE Symposium on Security and Privacy (Oakland) 2013 + +[SCIPR Lab]: http://www.scipr-lab.org/ (Succinct Computational Integrity and Privacy Research Lab) + +[LICENSE]: LICENSE (LICENSE file in top directory of libsnark distribution) + +[AUTHORS]: AUTHORS (AUTHORS file in top directory of libsnark distribution) diff --git a/privacy/zsl/zsl/snark/libsnark/doxygen.conf b/privacy/zsl/zsl/snark/libsnark/doxygen.conf new file mode 100644 index 0000000..5fbe616 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/doxygen.conf @@ -0,0 +1,1807 @@ +# Doxyfile 1.8.2 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project +# +# All text after a hash (#) is considered a comment and will be ignored +# The format is: +# TAG = value [value, ...] +# For lists items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (" ") + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the config file +# that follow. The default is UTF-8 which is also the encoding used for all +# text before the first occurrence of this tag. Doxygen uses libiconv (or the +# iconv built into libc) for the transcoding. See +# http://www.gnu.org/software/libiconv for the list of possible encodings. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or sequence of words) that should +# identify the project. Note that if you do not use Doxywizard you need +# to put quotes around the project name if it contains spaces. + +PROJECT_NAME = libsnark + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. +# This could be handy for archiving the generated documentation or +# if some version control system is used. + +PROJECT_NUMBER = + +# Using the PROJECT_BRIEF tag one can provide an optional one line description +# for a project that appears at the top of each page and should give viewer +# a quick idea about the purpose of the project. Keep the description short. + +PROJECT_BRIEF = + +# With the PROJECT_LOGO tag one can specify an logo or icon that is +# included in the documentation. The maximum height of the logo should not +# exceed 55 pixels and the maximum width should not exceed 200 pixels. +# Doxygen will copy the logo to the output directory. + +PROJECT_LOGO = + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) +# base path where the generated documentation will be put. +# If a relative path is entered, it will be relative to the location +# where doxygen was started. If left blank the current directory will be used. + +OUTPUT_DIRECTORY = + +# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create +# 4096 sub-directories (in 2 levels) under the output directory of each output +# format and will distribute the generated files over these directories. +# Enabling this option can be useful when feeding doxygen a huge amount of +# source files, where putting all generated files in the same directory would +# otherwise cause performance problems for the file system. + +CREATE_SUBDIRS = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# The default language is English, other supported languages are: +# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, +# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German, +# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English +# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, +# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak, +# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will +# include brief member descriptions after the members that are listed in +# the file and class documentation (similar to JavaDoc). +# Set to NO to disable this. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend +# the brief description of a member or function before the detailed description. +# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator +# that is used to form the text in various listings. Each string +# in this list, if found as the leading text of the brief description, will be +# stripped from the text and the result after processing the whole list, is +# used as the annotated text. Otherwise, the brief description is used as-is. +# If left blank, the following values are used ("$name" is automatically +# replaced with the name of the entity): "The $name class" "The $name widget" +# "The $name file" "is" "provides" "specifies" "contains" +# "represents" "a" "an" "the" + +ABBREVIATE_BRIEF = + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# Doxygen will generate a detailed section even if there is only a brief +# description. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full +# path before files name in the file list and in the header files. If set +# to NO the shortest path that makes the file name unique will be used. + +FULL_PATH_NAMES = YES + +# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag +# can be used to strip a user-defined part of the path. Stripping is +# only done if one of the specified strings matches the left-hand part of +# the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the +# path to strip. Note that you specify absolute paths here, but also +# relative paths, which will be relative from the directory where doxygen is +# started. + +STRIP_FROM_PATH = src + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of +# the path mentioned in the documentation of a class, which tells +# the reader which header file to include in order to use a class. +# If left blank only the name of the header file containing the class +# definition is used. Otherwise one should specify the include paths that +# are normally passed to the compiler using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter +# (but less readable) file names. This can be useful if your file system +# doesn't support long names like on DOS, Mac, or CD-ROM. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen +# will interpret the first line (until the first dot) of a JavaDoc-style +# comment as the brief description. If set to NO, the JavaDoc +# comments will behave just like regular Qt-style comments +# (thus requiring an explicit @brief command for a brief description.) + +JAVADOC_AUTOBRIEF = YES + +# If the QT_AUTOBRIEF tag is set to YES then Doxygen will +# interpret the first line (until the first dot) of a Qt-style +# comment as the brief description. If set to NO, the comments +# will behave just like regular Qt-style comments (thus requiring +# an explicit \brief command for a brief description.) + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen +# treat a multi-line C++ special comment block (i.e. a block of //! or /// +# comments) as a brief description. This used to be the default behaviour. +# The new default is to treat a multi-line C++ comment block as a detailed +# description. Set this tag to YES if you prefer the old behaviour instead. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented +# member inherits the documentation from any documented member that it +# re-implements. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce +# a new page for each member. If set to NO, the documentation of a member will +# be part of the file/class/namespace that contains it. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. +# Doxygen uses this value to replace tabs by spaces in code fragments. + +TAB_SIZE = 8 + +# This tag can be used to specify a number of aliases that acts +# as commands in the documentation. An alias has the form "name=value". +# For example adding "sideeffect=\par Side Effects:\n" will allow you to +# put the command \sideeffect (or @sideeffect) in the documentation, which +# will result in a user-defined paragraph with heading "Side Effects:". +# You can put \n's in the value part of an alias to insert newlines. + +ALIASES = + +# This tag can be used to specify a number of word-keyword mappings (TCL only). +# A mapping has the form "name=value". For example adding +# "class=itcl::class" will allow you to use the command class in the +# itcl::class meaning. + +TCL_SUBST = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C +# sources only. Doxygen will then generate output that is more tailored for C. +# For instance, some of the names that are used will be different. The list +# of all members will be omitted, etc. + +OPTIMIZE_OUTPUT_FOR_C = NO + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java +# sources only. Doxygen will then generate output that is more tailored for +# Java. For instance, namespaces will be presented as packages, qualified +# scopes will look different, etc. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources only. Doxygen will then generate output that is more tailored for +# Fortran. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for +# VHDL. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Doxygen selects the parser to use depending on the extension of the files it +# parses. With this tag you can assign which parser to use for a given +# extension. Doxygen has a built-in mapping, but you can override or extend it +# using this tag. The format is ext=language, where ext is a file extension, +# and language is one of the parsers supported by doxygen: IDL, Java, +# Javascript, CSharp, C, C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, +# C++. For instance to make doxygen treat .inc files as Fortran files (default +# is PHP), and .f files as C (default is Fortran), use: inc=Fortran f=C. Note +# that for custom extensions you also need to set FILE_PATTERNS otherwise the +# files are not read by doxygen. + +EXTENSION_MAPPING = tcc=C++ + +# If MARKDOWN_SUPPORT is enabled (the default) then doxygen pre-processes all +# comments according to the Markdown format, which allows for more readable +# documentation. See http://daringfireball.net/projects/markdown/ for details. +# The output of markdown processing is further processed by doxygen, so you +# can mix doxygen, HTML, and XML commands with Markdown formatting. +# Disable only in case of backward compatibilities issues. + +MARKDOWN_SUPPORT = YES + +# When enabled doxygen tries to link words that correspond to documented classes, +# or namespaces to their corresponding documentation. Such a link can be +# prevented in individual cases by by putting a % sign in front of the word or +# globally by setting AUTOLINK_SUPPORT to NO. + +AUTOLINK_SUPPORT = YES + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should +# set this tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. +# func(std::string) {}). This also makes the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. + +BUILTIN_STL_SUPPORT = NO + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. +# Doxygen will parse them like normal C++ but will assume all classes use public +# instead of private inheritance when no explicit protection keyword is present. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate +# getter and setter methods for a property. Setting this option to YES (the +# default) will make doxygen replace the get and set methods by a property in +# the documentation. This will only work if the methods are indeed getting or +# setting a simple type. If this is not the case, or you want to show the +# methods anyway, you should set this option to NO. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. + +DISTRIBUTE_GROUP_DOC = NO + +# Set the SUBGROUPING tag to YES (the default) to allow class member groups of +# the same type (for instance a group of public functions) to be put as a +# subgroup of that type (e.g. under the Public Functions section). Set it to +# NO to prevent subgrouping. Alternatively, this can be done per class using +# the \nosubgrouping command. + +SUBGROUPING = YES + +# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and +# unions are shown inside the group in which they are included (e.g. using +# @ingroup) instead of on a separate page (for HTML and Man pages) or +# section (for LaTeX and RTF). + +INLINE_GROUPED_CLASSES = NO + +# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and +# unions with only public data fields will be shown inline in the documentation +# of the scope in which they are defined (i.e. file, namespace, or group +# documentation), provided this scope is documented. If set to NO (the default), +# structs, classes, and unions are shown on a separate page (for HTML and Man +# pages) or section (for LaTeX and RTF). + +INLINE_SIMPLE_STRUCTS = NO + +# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum +# is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically +# be useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. + +TYPEDEF_HIDES_STRUCT = NO + +# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to +# determine which symbols to keep in memory and which to flush to disk. +# When the cache is full, less often used symbols will be written to disk. +# For small to medium size projects (<1000 input files) the default value is +# probably good enough. For larger projects a too small cache size can cause +# doxygen to be busy swapping symbols to and from disk most of the time +# causing a significant performance penalty. +# If the system has enough physical memory increasing the cache will improve the +# performance by keeping more symbols in memory. Note that the value works on +# a logarithmic scale so increasing the size by one will roughly double the +# memory usage. The cache size is given by this formula: +# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, +# corresponding to a cache size of 2^16 = 65536 symbols. + +SYMBOL_CACHE_SIZE = 0 + +# Similar to the SYMBOL_CACHE_SIZE the size of the symbol lookup cache can be +# set using LOOKUP_CACHE_SIZE. This cache is used to resolve symbols given +# their name and scope. Since this can be an expensive process and often the +# same symbol appear multiple times in the code, doxygen keeps a cache of +# pre-resolved symbols. If the cache is too small doxygen will become slower. +# If the cache is too large, memory is wasted. The cache size is given by this +# formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range is 0..9, the default is 0, +# corresponding to a cache size of 2^16 = 65536 symbols. + +LOOKUP_CACHE_SIZE = 0 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. +# Private class members and static file members will be hidden unless +# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES + +EXTRACT_ALL = YES + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class +# will be included in the documentation. + +EXTRACT_PRIVATE = YES + +# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal +# scope will be included in the documentation. + +EXTRACT_PACKAGE = NO + +# If the EXTRACT_STATIC tag is set to YES all static members of a file +# will be included in the documentation. + +EXTRACT_STATIC = YES + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) +# defined locally in source files will be included in the documentation. +# If set to NO only classes defined in header files are included. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. When set to YES local +# methods, which are defined in the implementation section but not in +# the interface are included in the documentation. +# If set to NO (the default) only methods in the interface are included. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base +# name of the file that contains the anonymous namespace. By default +# anonymous namespaces are hidden. + +EXTRACT_ANON_NSPACES = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all +# undocumented members of documented classes, files or namespaces. +# If set to NO (the default) these members will be included in the +# various overviews, but no documentation section is generated. +# This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. +# If set to NO (the default) these classes will be included in the various +# overviews. This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all +# friend (class|struct|union) declarations. +# If set to NO (the default) these declarations will be included in the +# documentation. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any +# documentation blocks found inside the body of a function. +# If set to NO (the default) these blocks will be appended to the +# function's detailed documentation block. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation +# that is typed after a \internal command is included. If the tag is set +# to NO (the default) then the documentation will be excluded. +# Set it to YES to include the internal documentation. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate +# file names in lower-case letters. If set to YES upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. + +CASE_SENSE_NAMES = YES + +# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen +# will show members with their full class and namespace scopes in the +# documentation. If set to YES the scope will be hidden. + +HIDE_SCOPE_NAMES = NO + +# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen +# will put a list of the files that are included by a file in the documentation +# of that file. + +SHOW_INCLUDE_FILES = YES + +# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen +# will list include files with double quotes in the documentation +# rather than with sharp brackets. + +FORCE_LOCAL_INCLUDES = NO + +# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] +# is inserted in the documentation for inline members. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen +# will sort the (detailed) documentation of file and class members +# alphabetically by member name. If set to NO the members will appear in +# declaration order. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the +# brief documentation of file, namespace and class members alphabetically +# by member name. If set to NO (the default) the members will appear in +# declaration order. + +SORT_BRIEF_DOCS = NO + +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen +# will sort the (brief and detailed) documentation of class members so that +# constructors and destructors are listed first. If set to NO (the default) +# the constructors will appear in the respective orders defined by +# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. +# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO +# and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO. + +SORT_MEMBERS_CTORS_1ST = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the +# hierarchy of group names into alphabetical order. If set to NO (the default) +# the group names will appear in their defined order. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be +# sorted by fully-qualified names, including namespaces. If set to +# NO (the default), the class list will be sorted only by class name, +# not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the +# alphabetical list. + +SORT_BY_SCOPE_NAME = NO + +# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to +# do proper type resolution of all parameters of a function it will reject a +# match between the prototype and the implementation of a member function even +# if there is only one candidate or it is obvious which candidate to choose +# by doing a simple string match. By disabling STRICT_PROTO_MATCHING doxygen +# will still accept a match between prototype and implementation in such cases. + +STRICT_PROTO_MATCHING = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or +# disable (NO) the todo list. This list is created by putting \todo +# commands in the documentation. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or +# disable (NO) the test list. This list is created by putting \test +# commands in the documentation. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or +# disable (NO) the bug list. This list is created by putting \bug +# commands in the documentation. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or +# disable (NO) the deprecated list. This list is created by putting +# \deprecated commands in the documentation. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional +# documentation sections, marked by \if sectionname ... \endif. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines +# the initial value of a variable or macro consists of for it to appear in +# the documentation. If the initializer consists of more lines than specified +# here it will be hidden. Use a value of 0 to hide initializers completely. +# The appearance of the initializer of individual variables and macros in the +# documentation can be controlled using \showinitializer or \hideinitializer +# command in the documentation regardless of this setting. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated +# at the bottom of the documentation of classes and structs. If set to YES the +# list will mention the files that were used to generate the documentation. + +SHOW_USED_FILES = YES + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. +# This will remove the Files entry from the Quick Index and from the +# Folder Tree View (if specified). The default is YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the +# Namespaces page. This will remove the Namespaces entry from the Quick Index +# and from the Folder Tree View (if specified). The default is YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command , where is the value of +# the FILE_VERSION_FILTER tag, and is the name of an input file +# provided by doxygen. Whatever the program writes to standard output +# is used as the file version. See the manual for examples. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed +# by doxygen. The layout file controls the global structure of the generated +# output files in an output format independent way. To create the layout file +# that represents doxygen's defaults, run doxygen with the -l option. +# You can optionally specify a file name after the option, if omitted +# DoxygenLayout.xml will be used as the name of the layout file. + +LAYOUT_FILE = + +# The CITE_BIB_FILES tag can be used to specify one or more bib files +# containing the references data. This must be a list of .bib files. The +# .bib extension is automatically appended if omitted. Using this command +# requires the bibtex tool to be installed. See also +# http://en.wikipedia.org/wiki/BibTeX for more info. For LaTeX the style +# of the bibliography can be controlled using LATEX_BIB_STYLE. To use this +# feature you need bibtex and perl available in the search path. + +CITE_BIB_FILES = + +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated +# by doxygen. Possible values are YES and NO. If left blank NO is used. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated by doxygen. Possible values are YES and NO. If left blank +# NO is used. + +WARNINGS = YES + +# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings +# for undocumented members. If EXTRACT_ALL is set to YES then this flag will +# automatically be disabled. + +WARN_IF_UNDOCUMENTED = YES + +# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some +# parameters in a documented function, or documenting parameters that +# don't exist or using markup commands wrongly. + +WARN_IF_DOC_ERROR = YES + +# The WARN_NO_PARAMDOC option can be enabled to get warnings for +# functions that are documented, but have no documentation for their parameters +# or return value. If set to NO (the default) doxygen will only warn about +# wrong or incomplete parameter documentation, but not about the absence of +# documentation. + +WARN_NO_PARAMDOC = NO + +# The WARN_FORMAT tag determines the format of the warning messages that +# doxygen can produce. The string should contain the $file, $line, and $text +# tags, which will be replaced by the file and line number from which the +# warning originated and the warning text. Optionally the format may contain +# $version, which will be replaced by the version of the file (if it could +# be obtained via FILE_VERSION_FILTER) + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning +# and error messages should be written. If left blank the output is written +# to stderr. + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag can be used to specify the files and/or directories that contain +# documented source files. You may enter file names like "myfile.cpp" or +# directories like "/usr/src/myproject". Separate the files or directories +# with spaces. + +INPUT = src README.md + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is +# also the default input encoding. Doxygen uses libiconv (or the iconv built +# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for +# the list of possible encodings. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank the following patterns are tested: +# *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh +# *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py +# *.f90 *.f *.for *.vhd *.vhdl + +FILE_PATTERNS = *.md *.c *.h *.cpp *.hpp *.tcc *.inc *.cc + +# The RECURSIVE tag can be used to turn specify whether or not subdirectories +# should be searched for input files as well. Possible values are YES and NO. +# If left blank NO is used. + +RECURSIVE = YES + +# The EXCLUDE tag can be used to specify files and/or directories that should be +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. +# Note that relative paths are relative to the directory from which doxygen is +# run. + +EXCLUDE = Debug \ + Release + +# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or +# directories that are symbolic links (a Unix file system feature) are excluded +# from the input. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. Note that the wildcards are matched +# against the file with absolute path, so to exclude all test directories +# for example use the pattern */test/* + +EXCLUDE_PATTERNS = + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test + +EXCLUDE_SYMBOLS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or +# directories that contain example code fragments that are included (see +# the \include command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank all files are included. + +EXAMPLE_PATTERNS = + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude +# commands irrespective of the value of the RECURSIVE tag. +# Possible values are YES and NO. If left blank NO is used. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or +# directories that contain image that are included in the documentation (see +# the \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command , where +# is the value of the INPUT_FILTER tag, and is the name of an +# input file. Doxygen will then use the output that the filter program writes +# to standard output. If FILTER_PATTERNS is specified, this tag will be +# ignored. + +INPUT_FILTER = "perl -pe 's/^(libsnark: .*)$/$1 {#mainpage}/ if $.==1; s!//+ *(TODO|FIXME|XXX)!/// \\todo!'" + # The 1st replacement marks README.md as the main page. + # The 2nd replacement identifies additional TODO notations. + # These should be done with FILTER_PATTERNS instead, but it looks like shell escaping is different there. + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: +# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further +# info on how filters are used. If FILTER_PATTERNS is empty or if +# non of the patterns match the file name, INPUT_FILTER is applied. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will be used to filter the input files when producing source +# files to browse (i.e. when SOURCE_BROWSER is set to YES). + +FILTER_SOURCE_FILES = NO + +# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file +# pattern. A pattern will override the setting for FILTER_PATTERN (if any) +# and it is also possible to disable source filtering for a specific pattern +# using *.ext= (so without naming a filter). This option only has effect when +# FILTER_SOURCE_FILES is enabled. + +FILTER_SOURCE_PATTERNS = + +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will +# be generated. Documented entities will be cross-referenced with these sources. +# Note: To get rid of all source code in the generated output, make sure also +# VERBATIM_HEADERS is set to NO. + +SOURCE_BROWSER = YES + +# Setting the INLINE_SOURCES tag to YES will include the body +# of functions and classes directly in the documentation. + +INLINE_SOURCES = YES + +# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct +# doxygen to hide any special comment blocks from generated source code +# fragments. Normal C, C++ and Fortran comments will always remain visible. + +STRIP_CODE_COMMENTS = NO + +# If the REFERENCED_BY_RELATION tag is set to YES +# then for each documented function all documented +# functions referencing it will be listed. + +REFERENCED_BY_RELATION = NO + +# If the REFERENCES_RELATION tag is set to YES +# then for each documented function all documented entities +# called/used by that function will be listed. + +REFERENCES_RELATION = NO + +# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) +# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from +# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will +# link to the source code. Otherwise they will link to the documentation. + +REFERENCES_LINK_SOURCE = YES + +# If the USE_HTAGS tag is set to YES then the references to source code +# will point to the HTML generated by the htags(1) tool instead of doxygen +# built-in source browser. The htags tool is part of GNU's global source +# tagging system (see http://www.gnu.org/software/global/global.html). You +# will need version 4.8.6 or higher. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen +# will generate a verbatim copy of the header file for each class for +# which an include is specified. Set to NO to disable this. + +VERBATIM_HEADERS = YES + +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index +# of all compounds will be generated. Enable this if the project +# contains a lot of classes, structs, unions or interfaces. + +ALPHABETICAL_INDEX = YES + +# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then +# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns +# in which this list will be split (can be a number in the range [1..20]) + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all +# classes will be put under the same header in the alphabetical index. +# The IGNORE_PREFIX tag can be used to specify one or more prefixes that +# should be ignored while generating the index headers. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES (the default) Doxygen will +# generate HTML output. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `html' will be used as the default path. + +HTML_OUTPUT = doxygen + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for +# each generated HTML page (for example: .htm,.php,.asp). If it is left blank +# doxygen will generate files with .html extension. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a personal HTML header for +# each generated HTML page. If it is left blank doxygen will generate a +# standard header. Note that when using a custom header you are responsible +# for the proper inclusion of any scripts and style sheets that doxygen +# needs, which is dependent on the configuration options used. +# It is advised to generate a default header using "doxygen -w html +# header.html footer.html stylesheet.css YourConfigFile" and then modify +# that header. Note that the header is subject to change so you typically +# have to redo this when upgrading to a newer version of doxygen or when +# changing the value of configuration settings such as GENERATE_TREEVIEW! + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a personal HTML footer for +# each generated HTML page. If it is left blank doxygen will generate a +# standard footer. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading +# style sheet that is used by each HTML page. It can be used to +# fine-tune the look of the HTML output. If left blank doxygen will +# generate a default style sheet. Note that it is recommended to use +# HTML_EXTRA_STYLESHEET instead of this one, as it is more robust and this +# tag will in the future become obsolete. + +HTML_STYLESHEET = + +# The HTML_EXTRA_STYLESHEET tag can be used to specify an additional +# user-defined cascading style sheet that is included after the standard +# style sheets created by doxygen. Using this option one can overrule +# certain style aspects. This is preferred over using HTML_STYLESHEET +# since it does not replace the standard style sheet and is therefor more +# robust against future updates. Doxygen will copy the style sheet file to +# the output directory. + +HTML_EXTRA_STYLESHEET = + +# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the HTML output directory. Note +# that these files will be copied to the base HTML output directory. Use the +# $relpath$ marker in the HTML_HEADER and/or HTML_FOOTER files to load these +# files. In the HTML_STYLESHEET file, use the file name only. Also note that +# the files will be copied as-is; there are no commands or markers available. + +HTML_EXTRA_FILES = + +# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. +# Doxygen will adjust the colors in the style sheet and background images +# according to this color. Hue is specified as an angle on a colorwheel, +# see http://en.wikipedia.org/wiki/Hue for more information. +# For instance the value 0 represents red, 60 is yellow, 120 is green, +# 180 is cyan, 240 is blue, 300 purple, and 360 is red again. +# The allowed range is 0 to 359. + +HTML_COLORSTYLE_HUE = 220 + +# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of +# the colors in the HTML output. For a value of 0 the output will use +# grayscales only. A value of 255 will produce the most vivid colors. + +HTML_COLORSTYLE_SAT = 100 + +# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to +# the luminance component of the colors in the HTML output. Values below +# 100 gradually make the output lighter, whereas values above 100 make +# the output darker. The value divided by 100 is the actual gamma applied, +# so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2, +# and 100 does not change the gamma. + +HTML_COLORSTYLE_GAMMA = 80 + +# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML +# page will contain the date and time when the page was generated. Setting +# this to NO can help when comparing the output of multiple runs. + +HTML_TIMESTAMP = NO + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. + +HTML_DYNAMIC_SECTIONS = NO + +# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of +# entries shown in the various tree structured indices initially; the user +# can expand and collapse entries dynamically later on. Doxygen will expand +# the tree to such a level that at most the specified number of entries are +# visible (unless a fully collapsed tree already exceeds this amount). +# So setting the number of entries 1 will produce a full collapsed tree by +# default. 0 is a special value representing an infinite number of entries +# and will result in a full expanded tree by default. + +HTML_INDEX_NUM_ENTRIES = 0 + +# If the GENERATE_DOCSET tag is set to YES, additional index files +# will be generated that can be used as input for Apple's Xcode 3 +# integrated development environment, introduced with OSX 10.5 (Leopard). +# To create a documentation set, doxygen will generate a Makefile in the +# HTML output directory. Running make will produce the docset in that +# directory and running "make install" will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find +# it at startup. +# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html +# for more information. + +GENERATE_DOCSET = NO + +# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the +# feed. A documentation feed provides an umbrella under which multiple +# documentation sets from a single provider (such as a company or product suite) +# can be grouped. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that +# should uniquely identify the documentation set bundle. This should be a +# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen +# will append .docset to the name. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely +# identify the documentation publisher. This should be a reverse domain-name +# style string, e.g. com.mycompany.MyDocSet.documentation. + +DOCSET_PUBLISHER_ID = org.doxygen.Publisher + +# The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher. + +DOCSET_PUBLISHER_NAME = Publisher + +# If the GENERATE_HTMLHELP tag is set to YES, additional index files +# will be generated that can be used as input for tools like the +# Microsoft HTML help workshop to generate a compiled HTML help file (.chm) +# of the generated HTML documentation. + +GENERATE_HTMLHELP = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can +# be used to specify the file name of the resulting .chm file. You +# can add a path in front of the file if the result should not be +# written to the html output directory. + +CHM_FILE = + +# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can +# be used to specify the location (absolute path including file name) of +# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run +# the HTML help compiler on the generated index.hhp. + +HHC_LOCATION = + +# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag +# controls if a separate .chi index file is generated (YES) or that +# it should be included in the master .chm file (NO). + +GENERATE_CHI = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING +# is used to encode HtmlHelp index (hhk), content (hhc) and project file +# content. + +CHM_INDEX_ENCODING = + +# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag +# controls whether a binary table of contents is generated (YES) or a +# normal table of contents (NO) in the .chm file. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members +# to the contents of the HTML help documentation and to the tree view. + +TOC_EXPAND = NO + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and +# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated +# that can be used as input for Qt's qhelpgenerator to generate a +# Qt Compressed Help (.qch) of the generated HTML documentation. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can +# be used to specify the file name of the resulting .qch file. +# The path specified is relative to the HTML output folder. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#namespace + +QHP_NAMESPACE = org.doxygen.Project + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#virtual-folders + +QHP_VIRTUAL_FOLDER = doc + +# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to +# add. For more information please see +# http://doc.trolltech.com/qthelpproject.html#custom-filters + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the +# custom filter to add. For more information please see +# +# Qt Help Project / Custom Filters. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this +# project's +# filter section matches. +# +# Qt Help Project / Filter Attributes. + +QHP_SECT_FILTER_ATTRS = + +# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can +# be used to specify the location of Qt's qhelpgenerator. +# If non-empty doxygen will try to run qhelpgenerator on the generated +# .qhp file. + +QHG_LOCATION = + +# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files +# will be generated, which together with the HTML files, form an Eclipse help +# plugin. To install this plugin and make it available under the help contents +# menu in Eclipse, the contents of the directory containing the HTML and XML +# files needs to be copied into the plugins directory of eclipse. The name of +# the directory within the plugins directory should be the same as +# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before +# the help appears. + +GENERATE_ECLIPSEHELP = NO + +# A unique identifier for the eclipse help plugin. When installing the plugin +# the directory name containing the HTML and XML files should also have +# this name. + +ECLIPSE_DOC_ID = org.doxygen.Project + +# The DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) +# at top of each HTML page. The value NO (the default) enables the index and +# the value YES disables it. Since the tabs have the same information as the +# navigation tree you can set this option to NO if you already set +# GENERATE_TREEVIEW to YES. + +DISABLE_INDEX = NO + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. +# If the tag value is set to YES, a side panel will be generated +# containing a tree-like index structure (just like the one that +# is generated for HTML Help). For this to work a browser that supports +# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser). +# Windows users are probably better off using the HTML help feature. +# Since the tree basically has the same information as the tab index you +# could consider to set DISABLE_INDEX to NO when enabling this option. + +GENERATE_TREEVIEW = YES + +# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values +# (range [0,1..20]) that doxygen will group on one line in the generated HTML +# documentation. Note that a value of 0 will completely suppress the enum +# values from appearing in the overview section. + +ENUM_VALUES_PER_LINE = 4 + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be +# used to set the initial width (in pixels) of the frame in which the tree +# is shown. + +TREEVIEW_WIDTH = 250 + +# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open +# links to external symbols imported via tag files in a separate window. + +EXT_LINKS_IN_WINDOW = NO + +# Use this tag to change the font size of Latex formulas included +# as images in the HTML documentation. The default is 10. Note that +# when you change the font size after a successful doxygen run you need +# to manually remove any form_*.png images from the HTML output directory +# to force them to be regenerated. + +FORMULA_FONTSIZE = 10 + +# Use the FORMULA_TRANPARENT tag to determine whether or not the images +# generated for formulas are transparent PNGs. Transparent PNGs are +# not supported properly for IE 6.0, but are supported on all modern browsers. +# Note that when changing this option you need to delete any form_*.png files +# in the HTML output before the changes have effect. + +FORMULA_TRANSPARENT = YES + +# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax +# (see http://www.mathjax.org) which uses client side Javascript for the +# rendering instead of using prerendered bitmaps. Use this if you do not +# have LaTeX installed or if you want to formulas look prettier in the HTML +# output. When enabled you may also need to install MathJax separately and +# configure the path to it using the MATHJAX_RELPATH option. + +USE_MATHJAX = YES + +# When MathJax is enabled you need to specify the location relative to the +# HTML output directory using the MATHJAX_RELPATH option. The destination +# directory should contain the MathJax.js script. For instance, if the mathjax +# directory is located at the same level as the HTML output directory, then +# MATHJAX_RELPATH should be ../mathjax. The default value points to +# the MathJax Content Delivery Network so you can quickly see the result without +# installing MathJax. However, it is strongly recommended to install a local +# copy of MathJax from http://www.mathjax.org before deployment. + +MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest + +# The MATHJAX_EXTENSIONS tag can be used to specify one or MathJax extension +# names that should be enabled during MathJax rendering. + +MATHJAX_EXTENSIONS = + +# When the SEARCHENGINE tag is enabled doxygen will generate a search box +# for the HTML output. The underlying search engine uses javascript +# and DHTML and should work on any modern browser. Note that when using +# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets +# (GENERATE_DOCSET) there is already a search function so this one should +# typically be disabled. For large projects the javascript based search engine +# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution. + +SEARCHENGINE = YES + +# When the SERVER_BASED_SEARCH tag is enabled the search engine will be +# implemented using a PHP enabled web server instead of at the web client +# using Javascript. Doxygen will generate the search PHP script and index +# file to put on the web server. The advantage of the server +# based approach is that it scales better to large projects and allows +# full text search. The disadvantages are that it is more difficult to setup +# and does not have live searching capabilities. + +SERVER_BASED_SEARCH = NO + +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will +# generate Latex output. + +GENERATE_LATEX = NO + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `latex' will be used as the default path. + +LATEX_OUTPUT = latex + +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be +# invoked. If left blank `latex' will be used as the default command name. +# Note that when enabling USE_PDFLATEX this option is only used for +# generating bitmaps for formulas in the HTML output, but not in the +# Makefile that is written to the output directory. + +LATEX_CMD_NAME = latex + +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to +# generate index for LaTeX. If left blank `makeindex' will be used as the +# default command name. + +MAKEINDEX_CMD_NAME = makeindex + +# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact +# LaTeX documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_LATEX = NO + +# The PAPER_TYPE tag can be used to set the paper type that is used +# by the printer. Possible values are: a4, letter, legal and +# executive. If left blank a4wide will be used. + +PAPER_TYPE = a4 + +# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX +# packages that should be included in the LaTeX output. + +EXTRA_PACKAGES = amsfonts + +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for +# the generated latex document. The header should contain everything until +# the first chapter. If it is left blank doxygen will generate a +# standard header. Notice: only use this tag if you know what you are doing! + +LATEX_HEADER = + +# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for +# the generated latex document. The footer should contain everything after +# the last chapter. If it is left blank doxygen will generate a +# standard footer. Notice: only use this tag if you know what you are doing! + +LATEX_FOOTER = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated +# is prepared for conversion to pdf (using ps2pdf). The pdf file will +# contain links (just like the HTML output) instead of page references +# This makes the output suitable for online browsing using a pdf viewer. + +PDF_HYPERLINKS = NO + +# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of +# plain latex in the generated Makefile. Set this option to YES to get a +# higher quality PDF documentation. + +USE_PDFLATEX = NO + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. +# command to the generated LaTeX files. This will instruct LaTeX to keep +# running if errors occur, instead of asking the user for help. +# This option is also used when generating formulas in HTML. + +LATEX_BATCHMODE = NO + +# If LATEX_HIDE_INDICES is set to YES then doxygen will not +# include the index chapters (such as File Index, Compound Index, etc.) +# in the output. + +LATEX_HIDE_INDICES = NO + +# If LATEX_SOURCE_CODE is set to YES then doxygen will include +# source code with syntax highlighting in the LaTeX output. +# Note that which sources are shown also depends on other settings +# such as SOURCE_BROWSER. + +LATEX_SOURCE_CODE = NO + +# The LATEX_BIB_STYLE tag can be used to specify the style to use for the +# bibliography, e.g. plainnat, or ieeetr. The default style is "plain". See +# http://en.wikipedia.org/wiki/BibTeX for more info. + +LATEX_BIB_STYLE = plain + +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output +# The RTF output is optimized for Word 97 and may not look very pretty with +# other RTF readers or editors. + +GENERATE_RTF = NO + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `rtf' will be used as the default path. + +RTF_OUTPUT = rtf + +# If the COMPACT_RTF tag is set to YES Doxygen generates more compact +# RTF documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_RTF = NO + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated +# will contain hyperlink fields. The RTF file will +# contain links (just like the HTML output) instead of page references. +# This makes the output suitable for online browsing using WORD or other +# programs which support those fields. +# Note: wordpad (write) and others do not support links. + +RTF_HYPERLINKS = NO + +# Load style sheet definitions from file. Syntax is similar to doxygen's +# config file, i.e. a series of assignments. You only have to provide +# replacements, missing definitions are set to their default value. + +RTF_STYLESHEET_FILE = + +# Set optional variables used in the generation of an rtf document. +# Syntax is similar to doxygen's config file. + +RTF_EXTENSIONS_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES (the default) Doxygen will +# generate man pages + +GENERATE_MAN = NO + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `man' will be used as the default path. + +MAN_OUTPUT = man + +# The MAN_EXTENSION tag determines the extension that is added to +# the generated man pages (default is the subroutine's section .3) + +MAN_EXTENSION = .3 + +# If the MAN_LINKS tag is set to YES and Doxygen generates man output, +# then it will generate one additional man file for each entity +# documented in the real man page(s). These additional files +# only source the real man page, but without them the man command +# would be unable to find the correct page. The default is NO. + +MAN_LINKS = NO + +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES Doxygen will +# generate an XML file that captures the structure of +# the code including all documentation. + +GENERATE_XML = NO + +# The XML_OUTPUT tag is used to specify where the XML pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `xml' will be used as the default path. + +XML_OUTPUT = xml + +# The XML_SCHEMA tag can be used to specify an XML schema, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_SCHEMA = + +# The XML_DTD tag can be used to specify an XML DTD, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_DTD = + +# If the XML_PROGRAMLISTING tag is set to YES Doxygen will +# dump the program listings (including syntax highlighting +# and cross-referencing information) to the XML output. Note that +# enabling this will significantly increase the size of the XML output. + +XML_PROGRAMLISTING = YES + +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- + +# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will +# generate an AutoGen Definitions (see autogen.sf.net) file +# that captures the structure of the code including all +# documentation. Note that this feature is still experimental +# and incomplete at the moment. + +GENERATE_AUTOGEN_DEF = NO + +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- + +# If the GENERATE_PERLMOD tag is set to YES Doxygen will +# generate a Perl module file that captures the structure of +# the code including all documentation. Note that this +# feature is still experimental and incomplete at the +# moment. + +GENERATE_PERLMOD = NO + +# If the PERLMOD_LATEX tag is set to YES Doxygen will generate +# the necessary Makefile rules, Perl scripts and LaTeX code to be able +# to generate PDF and DVI output from the Perl module output. + +PERLMOD_LATEX = NO + +# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be +# nicely formatted so it can be parsed by a human reader. This is useful +# if you want to understand what is going on. On the other hand, if this +# tag is set to NO the size of the Perl module output will be much smaller +# and Perl will parse it just the same. + +PERLMOD_PRETTY = YES + +# The names of the make variables in the generated doxyrules.make file +# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. +# This is useful so different doxyrules.make files included by the same +# Makefile don't overwrite each other's variables. + +PERLMOD_MAKEVAR_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will +# evaluate all C-preprocessor directives found in the sources and include +# files. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro +# names in the source code. If set to NO (the default) only conditional +# compilation will be performed. Macro expansion can be done in a controlled +# way by setting EXPAND_ONLY_PREDEF to YES. + +MACRO_EXPANSION = NO + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES +# then the macro expansion is limited to the macros specified with the +# PREDEFINED and EXPAND_AS_DEFINED tags. + +EXPAND_ONLY_PREDEF = NO + +# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files +# pointed to by INCLUDE_PATH will be searched when a #include is found. + +SEARCH_INCLUDES = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by +# the preprocessor. + +INCLUDE_PATH = + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will +# be used. + +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that +# are defined before the preprocessor is started (similar to the -D option of +# gcc). The argument of the tag is a list of macros of the form: name +# or name=definition (no spaces). If the definition and the = are +# omitted =1 is assumed. To prevent a macro definition from being +# undefined via #undef or recursively expanded use the := operator +# instead of the = operator. + +PREDEFINED = + +# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then +# this tag can be used to specify a list of macro names that should be expanded. +# The macro definition that is found in the sources will be used. +# Use the PREDEFINED tag if you want to use a different macro definition that +# overrules the definition found in the source code. + +EXPAND_AS_DEFINED = + +# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then +# doxygen's preprocessor will remove all references to function-like macros +# that are alone on a line, have an all uppercase name, and do not end with a +# semicolon, because these will confuse the parser if not removed. + +SKIP_FUNCTION_MACROS = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES option can be used to specify one or more tagfiles. For each +# tag file the location of the external documentation should be added. The +# format of a tag file without this location is as follows: +# TAGFILES = file1 file2 ... +# Adding location for the tag files is done as follows: +# TAGFILES = file1=loc1 "file2 = loc2" ... +# where "loc1" and "loc2" can be relative or absolute paths +# or URLs. Note that each tag file must have a unique name (where the name does +# NOT include the path). If a tag file is not located in the directory in which +# doxygen is run, you must also specify the path to the tagfile here. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create +# a tag file that is based on the input files it reads. + +GENERATE_TAGFILE = + +# If the ALLEXTERNALS tag is set to YES all external classes will be listed +# in the class index. If set to NO only the inherited external classes +# will be listed. + +ALLEXTERNALS = NO + +# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will +# be listed. + +EXTERNAL_GROUPS = YES + +# The PERL_PATH should be the absolute path and name of the perl script +# interpreter (i.e. the result of `which perl'). + +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will +# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base +# or super classes. Setting the tag to NO turns the diagrams off. Note that +# this option also works with HAVE_DOT disabled, but it is recommended to +# install and use dot, since it yields more powerful graphs. + +CLASS_DIAGRAMS = NO + +# You can define message sequence charts within doxygen comments using the \msc +# command. Doxygen will then run the mscgen tool (see +# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the +# documentation. The MSCGEN_PATH tag allows you to specify the directory where +# the mscgen tool resides. If left empty the tool is assumed to be found in the +# default search path. + +MSCGEN_PATH = + +# If set to YES, the inheritance and collaboration graphs will hide +# inheritance and usage relations if the target is undocumented +# or is not a class. + +HIDE_UNDOC_RELATIONS = YES + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz, a graph visualization +# toolkit from AT&T and Lucent Bell Labs. The other options in this section +# have no effect if this option is set to NO (the default) + +HAVE_DOT = YES + +# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is +# allowed to run in parallel. When set to 0 (the default) doxygen will +# base this on the number of processors available in the system. You can set it +# explicitly to a value larger than 0 to get control over the balance +# between CPU load and processing speed. + +DOT_NUM_THREADS = 0 + +# By default doxygen will use the Helvetica font for all dot files that +# doxygen generates. When you want a differently looking font you can specify +# the font name using DOT_FONTNAME. You need to make sure dot is able to find +# the font, which can be done by putting it in a standard location or by setting +# the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the +# directory containing the font. + +DOT_FONTNAME = Helvetica + +# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. +# The default size is 10pt. + +DOT_FONTSIZE = 10 + +# By default doxygen will tell dot to use the Helvetica font. +# If you specify a different font using DOT_FONTNAME you can use DOT_FONTPATH to +# set the path where dot can find it. + +DOT_FONTPATH = + +# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect inheritance relations. Setting this tag to YES will force the +# CLASS_DIAGRAMS tag to NO. + +CLASS_GRAPH = YES + +# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect implementation dependencies (inheritance, containment, and +# class references variables) of the class with other documented classes. + +COLLABORATION_GRAPH = YES + +# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for groups, showing the direct groups dependencies + +GROUP_GRAPHS = YES + +# If the UML_LOOK tag is set to YES doxygen will generate inheritance and +# collaboration diagrams in a style similar to the OMG's Unified Modeling +# Language. + +UML_LOOK = NO + +# If the UML_LOOK tag is enabled, the fields and methods are shown inside +# the class node. If there are many fields or methods and many nodes the +# graph may become too big to be useful. The UML_LIMIT_NUM_FIELDS +# threshold limits the number of items for each type to make the size more +# managable. Set this to 0 for no limit. Note that the threshold may be +# exceeded by 50% before the limit is enforced. + +UML_LIMIT_NUM_FIELDS = 10 + +# If set to YES, the inheritance and collaboration graphs will show the +# relations between templates and their instances. + +TEMPLATE_RELATIONS = NO + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT +# tags are set to YES then doxygen will generate a graph for each documented +# file showing the direct and indirect include dependencies of the file with +# other documented files. + +INCLUDE_GRAPH = YES + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and +# HAVE_DOT tags are set to YES then doxygen will generate a graph for each +# documented header file showing the documented files that directly or +# indirectly include this file. + +INCLUDED_BY_GRAPH = YES + +# If the CALL_GRAPH and HAVE_DOT options are set to YES then +# doxygen will generate a call dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable call graphs +# for selected functions only using the \callgraph command. + +CALL_GRAPH = YES + +# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then +# doxygen will generate a caller dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable caller +# graphs for selected functions only using the \callergraph command. + +CALLER_GRAPH = YES + +# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen +# will generate a graphical hierarchy of all classes instead of a textual one. + +GRAPHICAL_HIERARCHY = YES + +# If the DIRECTORY_GRAPH and HAVE_DOT tags are set to YES +# then doxygen will show the dependencies a directory has on other directories +# in a graphical way. The dependency relations are determined by the #include +# relations between the files in the directories. + +DIRECTORY_GRAPH = YES + +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# generated by dot. Possible values are svg, png, jpg, or gif. +# If left blank png will be used. If you choose svg you need to set +# HTML_FILE_EXTENSION to xhtml in order to make the SVG files +# visible in IE 9+ (other browsers do not have this requirement). + +DOT_IMAGE_FORMAT = png + +# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to +# enable generation of interactive SVG images that allow zooming and panning. +# Note that this requires a modern browser other than Internet Explorer. +# Tested and working are Firefox, Chrome, Safari, and Opera. For IE 9+ you +# need to set HTML_FILE_EXTENSION to xhtml in order to make the SVG files +# visible. Older versions of IE do not have SVG support. + +INTERACTIVE_SVG = NO + +# The tag DOT_PATH can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found in the path. + +DOT_PATH = + +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the +# \dotfile command). + +DOTFILE_DIRS = + +# The MSCFILE_DIRS tag can be used to specify one or more directories that +# contain msc files that are included in the documentation (see the +# \mscfile command). + +MSCFILE_DIRS = + +# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of +# nodes that will be shown in the graph. If the number of nodes in a graph +# becomes larger than this value, doxygen will truncate the graph, which is +# visualized by representing a node as a red box. Note that doxygen if the +# number of direct children of the root node in a graph is already larger than +# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note +# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. + +DOT_GRAPH_MAX_NODES = 50 + +# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the +# graphs generated by dot. A depth value of 3 means that only nodes reachable +# from the root by following a path via at most 3 edges will be shown. Nodes +# that lay further from the root node will be omitted. Note that setting this +# option to 1 or 2 may greatly reduce the computation time needed for large +# code bases. Also note that the size of a graph can be further restricted by +# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. + +MAX_DOT_GRAPH_DEPTH = 0 + +# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent +# background. This is disabled by default, because dot on Windows does not +# seem to support this out of the box. Warning: Depending on the platform used, +# enabling this option may lead to badly anti-aliased labels on the edges of +# a graph (i.e. they become hard to read). + +DOT_TRANSPARENT = NO + +# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output +# files in one run (i.e. multiple -o and -T options on the command line). This +# makes dot run faster, but since only newer versions of dot (>1.8.10) +# support this, this feature is disabled by default. + +DOT_MULTI_TARGETS = NO + +# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will +# generate a legend page explaining the meaning of the various boxes and +# arrows in the dot generated graphs. + +GENERATE_LEGEND = YES + +# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will +# remove the intermediate dot files that are used to generate +# the various graphs. + +DOT_CLEANUP = YES diff --git a/privacy/zsl/zsl/snark/libsnark/prepare-depends.sh b/privacy/zsl/zsl/snark/libsnark/prepare-depends.sh new file mode 100755 index 0000000..0592904 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/prepare-depends.sh @@ -0,0 +1,31 @@ +#!/bin/sh +# This script fetches, builds and locally installs external dependencies. + +set -x -e + +DEPSRC=./depsrc +DEPINST=./depinst + +# rm -fr $DEPINST +mkdir -p $DEPINST +mkdir -p $DEPSRC + +# ate-pairing library, and its dependency, xbyak (needed for BN128 curve) +cd $DEPSRC +[ ! -d xbyak ] && git clone git://github.com/herumi/xbyak.git +[ ! -d ate-pairing ] && git clone git://github.com/herumi/ate-pairing.git +cd ate-pairing +make -j SUPPORT_SNARK=1 +cd ../.. +cp -rv $DEPSRC/ate-pairing/include $DEPINST/ +cp -rv $DEPSRC/ate-pairing/lib $DEPINST/ + +# SUPERCOP library (optimized crypto implementations, used by ADSNARK) +cd $DEPSRC +[ ! -d libsnark-supercop ] && git clone git://github.com/mbbarbosa/libsnark-supercop.git +cd libsnark-supercop +sh "do" +cd ../.. +mkdir -p $DEPINST/include/supercop +cp -v $DEPSRC/libsnark-supercop/include/* $DEPINST/include/supercop +cp -rv $DEPSRC/libsnark-supercop/lib $DEPINST/ diff --git a/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/alt_bn128/alt_bn128_g1.cpp b/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/alt_bn128/alt_bn128_g1.cpp new file mode 100644 index 0000000..bf7f43d --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/alt_bn128/alt_bn128_g1.cpp @@ -0,0 +1,524 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include "algebra/curves/alt_bn128/alt_bn128_g1.hpp" + +namespace libsnark { + +#ifdef PROFILE_OP_COUNTS +long long alt_bn128_G1::add_cnt = 0; +long long alt_bn128_G1::dbl_cnt = 0; +#endif + +std::vector alt_bn128_G1::wnaf_window_table; +std::vector alt_bn128_G1::fixed_base_exp_window_table; +alt_bn128_G1 alt_bn128_G1::G1_zero; +alt_bn128_G1 alt_bn128_G1::G1_one; + +alt_bn128_G1::alt_bn128_G1() +{ + this->X = G1_zero.X; + this->Y = G1_zero.Y; + this->Z = G1_zero.Z; +} + +void alt_bn128_G1::print() const +{ + if (this->is_zero()) + { + printf("O\n"); + } + else + { + alt_bn128_G1 copy(*this); + copy.to_affine_coordinates(); + gmp_printf("(%Nd , %Nd)\n", + copy.X.as_bigint().data, alt_bn128_Fq::num_limbs, + copy.Y.as_bigint().data, alt_bn128_Fq::num_limbs); + } +} + +void alt_bn128_G1::print_coordinates() const +{ + if (this->is_zero()) + { + printf("O\n"); + } + else + { + gmp_printf("(%Nd : %Nd : %Nd)\n", + this->X.as_bigint().data, alt_bn128_Fq::num_limbs, + this->Y.as_bigint().data, alt_bn128_Fq::num_limbs, + this->Z.as_bigint().data, alt_bn128_Fq::num_limbs); + } +} + +void alt_bn128_G1::to_affine_coordinates() +{ + if (this->is_zero()) + { + this->X = alt_bn128_Fq::zero(); + this->Y = alt_bn128_Fq::one(); + this->Z = alt_bn128_Fq::zero(); + } + else + { + alt_bn128_Fq Z_inv = Z.inverse(); + alt_bn128_Fq Z2_inv = Z_inv.squared(); + alt_bn128_Fq Z3_inv = Z2_inv * Z_inv; + this->X = this->X * Z2_inv; + this->Y = this->Y * Z3_inv; + this->Z = alt_bn128_Fq::one(); + } +} + +void alt_bn128_G1::to_special() +{ + this->to_affine_coordinates(); +} + +bool alt_bn128_G1::is_special() const +{ + return (this->is_zero() || this->Z == alt_bn128_Fq::one()); +} + +bool alt_bn128_G1::is_zero() const +{ + return (this->Z.is_zero()); +} + +bool alt_bn128_G1::operator==(const alt_bn128_G1 &other) const +{ + if (this->is_zero()) + { + return other.is_zero(); + } + + if (other.is_zero()) + { + return false; + } + + /* now neither is O */ + + // using Jacobian coordinates so: + // (X1:Y1:Z1) = (X2:Y2:Z2) + // iff + // X1/Z1^2 == X2/Z2^2 and Y1/Z1^3 == Y2/Z2^3 + // iff + // X1 * Z2^2 == X2 * Z1^2 and Y1 * Z2^3 == Y2 * Z1^3 + + alt_bn128_Fq Z1_squared = (this->Z).squared(); + alt_bn128_Fq Z2_squared = (other.Z).squared(); + + if ((this->X * Z2_squared) != (other.X * Z1_squared)) + { + return false; + } + + alt_bn128_Fq Z1_cubed = (this->Z) * Z1_squared; + alt_bn128_Fq Z2_cubed = (other.Z) * Z2_squared; + + if ((this->Y * Z2_cubed) != (other.Y * Z1_cubed)) + { + return false; + } + + return true; +} + +bool alt_bn128_G1::operator!=(const alt_bn128_G1& other) const +{ + return !(operator==(other)); +} + +alt_bn128_G1 alt_bn128_G1::operator+(const alt_bn128_G1 &other) const +{ + // handle special cases having to do with O + if (this->is_zero()) + { + return other; + } + + if (other.is_zero()) + { + return *this; + } + + // no need to handle points of order 2,4 + // (they cannot exist in a prime-order subgroup) + + // check for doubling case + + // using Jacobian coordinates so: + // (X1:Y1:Z1) = (X2:Y2:Z2) + // iff + // X1/Z1^2 == X2/Z2^2 and Y1/Z1^3 == Y2/Z2^3 + // iff + // X1 * Z2^2 == X2 * Z1^2 and Y1 * Z2^3 == Y2 * Z1^3 + + alt_bn128_Fq Z1Z1 = (this->Z).squared(); + alt_bn128_Fq Z2Z2 = (other.Z).squared(); + + alt_bn128_Fq U1 = this->X * Z2Z2; + alt_bn128_Fq U2 = other.X * Z1Z1; + + alt_bn128_Fq Z1_cubed = (this->Z) * Z1Z1; + alt_bn128_Fq Z2_cubed = (other.Z) * Z2Z2; + + alt_bn128_Fq S1 = (this->Y) * Z2_cubed; // S1 = Y1 * Z2 * Z2Z2 + alt_bn128_Fq S2 = (other.Y) * Z1_cubed; // S2 = Y2 * Z1 * Z1Z1 + + if (U1 == U2 && S1 == S2) + { + // dbl case; nothing of above can be reused + return this->dbl(); + } + + // rest of add case + alt_bn128_Fq H = U2 - U1; // H = U2-U1 + alt_bn128_Fq S2_minus_S1 = S2-S1; + alt_bn128_Fq I = (H+H).squared(); // I = (2 * H)^2 + alt_bn128_Fq J = H * I; // J = H * I + alt_bn128_Fq r = S2_minus_S1 + S2_minus_S1; // r = 2 * (S2-S1) + alt_bn128_Fq V = U1 * I; // V = U1 * I + alt_bn128_Fq X3 = r.squared() - J - (V+V); // X3 = r^2 - J - 2 * V + alt_bn128_Fq S1_J = S1 * J; + alt_bn128_Fq Y3 = r * (V-X3) - (S1_J+S1_J); // Y3 = r * (V-X3)-2 S1 J + alt_bn128_Fq Z3 = ((this->Z+other.Z).squared()-Z1Z1-Z2Z2) * H; // Z3 = ((Z1+Z2)^2-Z1Z1-Z2Z2) * H + + return alt_bn128_G1(X3, Y3, Z3); +} + +alt_bn128_G1 alt_bn128_G1::operator-() const +{ + return alt_bn128_G1(this->X, -(this->Y), this->Z); +} + + +alt_bn128_G1 alt_bn128_G1::operator-(const alt_bn128_G1 &other) const +{ + return (*this) + (-other); +} + +alt_bn128_G1 alt_bn128_G1::add(const alt_bn128_G1 &other) const +{ + // handle special cases having to do with O + if (this->is_zero()) + { + return other; + } + + if (other.is_zero()) + { + return *this; + } + + // no need to handle points of order 2,4 + // (they cannot exist in a prime-order subgroup) + + // handle double case + if (this->operator==(other)) + { + return this->dbl(); + } + +#ifdef PROFILE_OP_COUNTS + this->add_cnt++; +#endif + // NOTE: does not handle O and pts of order 2,4 + // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-add-2007-bl + + alt_bn128_Fq Z1Z1 = (this->Z).squared(); // Z1Z1 = Z1^2 + alt_bn128_Fq Z2Z2 = (other.Z).squared(); // Z2Z2 = Z2^2 + alt_bn128_Fq U1 = (this->X) * Z2Z2; // U1 = X1 * Z2Z2 + alt_bn128_Fq U2 = (other.X) * Z1Z1; // U2 = X2 * Z1Z1 + alt_bn128_Fq S1 = (this->Y) * (other.Z) * Z2Z2; // S1 = Y1 * Z2 * Z2Z2 + alt_bn128_Fq S2 = (other.Y) * (this->Z) * Z1Z1; // S2 = Y2 * Z1 * Z1Z1 + alt_bn128_Fq H = U2 - U1; // H = U2-U1 + alt_bn128_Fq S2_minus_S1 = S2-S1; + alt_bn128_Fq I = (H+H).squared(); // I = (2 * H)^2 + alt_bn128_Fq J = H * I; // J = H * I + alt_bn128_Fq r = S2_minus_S1 + S2_minus_S1; // r = 2 * (S2-S1) + alt_bn128_Fq V = U1 * I; // V = U1 * I + alt_bn128_Fq X3 = r.squared() - J - (V+V); // X3 = r^2 - J - 2 * V + alt_bn128_Fq S1_J = S1 * J; + alt_bn128_Fq Y3 = r * (V-X3) - (S1_J+S1_J); // Y3 = r * (V-X3)-2 S1 J + alt_bn128_Fq Z3 = ((this->Z+other.Z).squared()-Z1Z1-Z2Z2) * H; // Z3 = ((Z1+Z2)^2-Z1Z1-Z2Z2) * H + + return alt_bn128_G1(X3, Y3, Z3); +} + +alt_bn128_G1 alt_bn128_G1::mixed_add(const alt_bn128_G1 &other) const +{ +#ifdef DEBUG + assert(other.is_special()); +#endif + + // handle special cases having to do with O + if (this->is_zero()) + { + return other; + } + + if (other.is_zero()) + { + return *this; + } + + // no need to handle points of order 2,4 + // (they cannot exist in a prime-order subgroup) + + // check for doubling case + + // using Jacobian coordinates so: + // (X1:Y1:Z1) = (X2:Y2:Z2) + // iff + // X1/Z1^2 == X2/Z2^2 and Y1/Z1^3 == Y2/Z2^3 + // iff + // X1 * Z2^2 == X2 * Z1^2 and Y1 * Z2^3 == Y2 * Z1^3 + + // we know that Z2 = 1 + + const alt_bn128_Fq Z1Z1 = (this->Z).squared(); + + const alt_bn128_Fq &U1 = this->X; + const alt_bn128_Fq U2 = other.X * Z1Z1; + + const alt_bn128_Fq Z1_cubed = (this->Z) * Z1Z1; + + const alt_bn128_Fq &S1 = (this->Y); // S1 = Y1 * Z2 * Z2Z2 + const alt_bn128_Fq S2 = (other.Y) * Z1_cubed; // S2 = Y2 * Z1 * Z1Z1 + + if (U1 == U2 && S1 == S2) + { + // dbl case; nothing of above can be reused + return this->dbl(); + } + +#ifdef PROFILE_OP_COUNTS + this->add_cnt++; +#endif + + // NOTE: does not handle O and pts of order 2,4 + // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-madd-2007-bl + alt_bn128_Fq H = U2-(this->X); // H = U2-X1 + alt_bn128_Fq HH = H.squared() ; // HH = H&2 + alt_bn128_Fq I = HH+HH; // I = 4*HH + I = I + I; + alt_bn128_Fq J = H*I; // J = H*I + alt_bn128_Fq r = S2-(this->Y); // r = 2*(S2-Y1) + r = r + r; + alt_bn128_Fq V = (this->X) * I ; // V = X1*I + alt_bn128_Fq X3 = r.squared()-J-V-V; // X3 = r^2-J-2*V + alt_bn128_Fq Y3 = (this->Y)*J; // Y3 = r*(V-X3)-2*Y1*J + Y3 = r*(V-X3) - Y3 - Y3; + alt_bn128_Fq Z3 = ((this->Z)+H).squared() - Z1Z1 - HH; // Z3 = (Z1+H)^2-Z1Z1-HH + + return alt_bn128_G1(X3, Y3, Z3); +} + +alt_bn128_G1 alt_bn128_G1::dbl() const +{ +#ifdef PROFILE_OP_COUNTS + this->dbl_cnt++; +#endif + // handle point at infinity + if (this->is_zero()) + { + return (*this); + } + + // no need to handle points of order 2,4 + // (they cannot exist in a prime-order subgroup) + + // NOTE: does not handle O and pts of order 2,4 + // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-dbl-2009-l + + alt_bn128_Fq A = (this->X).squared(); // A = X1^2 + alt_bn128_Fq B = (this->Y).squared(); // B = Y1^2 + alt_bn128_Fq C = B.squared(); // C = B^2 + alt_bn128_Fq D = (this->X + B).squared() - A - C; + D = D+D; // D = 2 * ((X1 + B)^2 - A - C) + alt_bn128_Fq E = A + A + A; // E = 3 * A + alt_bn128_Fq F = E.squared(); // F = E^2 + alt_bn128_Fq X3 = F - (D+D); // X3 = F - 2 D + alt_bn128_Fq eightC = C+C; + eightC = eightC + eightC; + eightC = eightC + eightC; + alt_bn128_Fq Y3 = E * (D - X3) - eightC; // Y3 = E * (D - X3) - 8 * C + alt_bn128_Fq Y1Z1 = (this->Y)*(this->Z); + alt_bn128_Fq Z3 = Y1Z1 + Y1Z1; // Z3 = 2 * Y1 * Z1 + + return alt_bn128_G1(X3, Y3, Z3); +} + +bool alt_bn128_G1::is_well_formed() const +{ + if (this->is_zero()) + { + return true; + } + else + { + /* + y^2 = x^3 + b + + We are using Jacobian coordinates, so equation we need to check is actually + + (y/z^3)^2 = (x/z^2)^3 + b + y^2 / z^6 = x^3 / z^6 + b + y^2 = x^3 + b z^6 + */ + alt_bn128_Fq X2 = this->X.squared(); + alt_bn128_Fq Y2 = this->Y.squared(); + alt_bn128_Fq Z2 = this->Z.squared(); + + alt_bn128_Fq X3 = this->X * X2; + alt_bn128_Fq Z3 = this->Z * Z2; + alt_bn128_Fq Z6 = Z3.squared(); + + return (Y2 == X3 + alt_bn128_coeff_b * Z6); + } +} + +alt_bn128_G1 alt_bn128_G1::zero() +{ + return G1_zero; +} + +alt_bn128_G1 alt_bn128_G1::one() +{ + return G1_one; +} + +alt_bn128_G1 alt_bn128_G1::random_element() +{ + return (scalar_field::random_element().as_bigint()) * G1_one; +} + +std::ostream& operator<<(std::ostream &out, const alt_bn128_G1 &g) +{ + alt_bn128_G1 copy(g); + copy.to_affine_coordinates(); + + out << (copy.is_zero() ? 1 : 0) << OUTPUT_SEPARATOR; +#ifdef NO_PT_COMPRESSION + out << copy.X << OUTPUT_SEPARATOR << copy.Y; +#else + /* storing LSB of Y */ + out << copy.X << OUTPUT_SEPARATOR << (copy.Y.as_bigint().data[0] & 1); +#endif + + return out; +} + +std::istream& operator>>(std::istream &in, alt_bn128_G1 &g) +{ + char is_zero; + alt_bn128_Fq tX, tY; + +#ifdef NO_PT_COMPRESSION + in >> is_zero >> tX >> tY; + is_zero -= '0'; +#else + in.read((char*)&is_zero, 1); // this reads is_zero; + is_zero -= '0'; + consume_OUTPUT_SEPARATOR(in); + + unsigned char Y_lsb; + in >> tX; + consume_OUTPUT_SEPARATOR(in); + in.read((char*)&Y_lsb, 1); + Y_lsb -= '0'; + + // y = +/- sqrt(x^3 + b) + if (!is_zero) + { + alt_bn128_Fq tX2 = tX.squared(); + alt_bn128_Fq tY2 = tX2*tX + alt_bn128_coeff_b; + tY = tY2.sqrt(); + + if ((tY.as_bigint().data[0] & 1) != Y_lsb) + { + tY = -tY; + } + } +#endif + // using Jacobian coordinates + if (!is_zero) + { + g.X = tX; + g.Y = tY; + g.Z = alt_bn128_Fq::one(); + } + else + { + g = alt_bn128_G1::zero(); + } + + return in; +} + +std::ostream& operator<<(std::ostream& out, const std::vector &v) +{ + out << v.size() << "\n"; + for (const alt_bn128_G1& t : v) + { + out << t << OUTPUT_NEWLINE; + } + + return out; +} + +std::istream& operator>>(std::istream& in, std::vector &v) +{ + v.clear(); + + size_t s; + in >> s; + consume_newline(in); + + v.reserve(s); + + for (size_t i = 0; i < s; ++i) + { + alt_bn128_G1 g; + in >> g; + consume_OUTPUT_NEWLINE(in); + v.emplace_back(g); + } + + return in; +} + +template<> +void batch_to_special_all_non_zeros(std::vector &vec) +{ + std::vector Z_vec; + Z_vec.reserve(vec.size()); + + for (auto &el: vec) + { + Z_vec.emplace_back(el.Z); + } + batch_invert(Z_vec); + + const alt_bn128_Fq one = alt_bn128_Fq::one(); + + for (size_t i = 0; i < vec.size(); ++i) + { + alt_bn128_Fq Z2 = Z_vec[i].squared(); + alt_bn128_Fq Z3 = Z_vec[i] * Z2; + + vec[i].X = vec[i].X * Z2; + vec[i].Y = vec[i].Y * Z3; + vec[i].Z = one; + } +} + +} // libsnark diff --git a/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/alt_bn128/alt_bn128_g1.hpp b/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/alt_bn128/alt_bn128_g1.hpp new file mode 100644 index 0000000..da11a2e --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/alt_bn128/alt_bn128_g1.hpp @@ -0,0 +1,95 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef ALT_BN128_G1_HPP_ +#define ALT_BN128_G1_HPP_ +#include +#include "algebra/curves/alt_bn128/alt_bn128_init.hpp" +#include "algebra/curves/curve_utils.hpp" + +namespace libsnark { + +class alt_bn128_G1; +std::ostream& operator<<(std::ostream &, const alt_bn128_G1&); +std::istream& operator>>(std::istream &, alt_bn128_G1&); + +class alt_bn128_G1 { +public: +#ifdef PROFILE_OP_COUNTS + static long long add_cnt; + static long long dbl_cnt; +#endif + static std::vector wnaf_window_table; + static std::vector fixed_base_exp_window_table; + static alt_bn128_G1 G1_zero; + static alt_bn128_G1 G1_one; + + typedef alt_bn128_Fq base_field; + typedef alt_bn128_Fr scalar_field; + + alt_bn128_Fq X, Y, Z; + + // using Jacobian coordinates + alt_bn128_G1(); + alt_bn128_G1(const alt_bn128_Fq& X, const alt_bn128_Fq& Y, const alt_bn128_Fq& Z) : X(X), Y(Y), Z(Z) {}; + + void print() const; + void print_coordinates() const; + + void to_affine_coordinates(); + void to_special(); + bool is_special() const; + + bool is_zero() const; + + bool operator==(const alt_bn128_G1 &other) const; + bool operator!=(const alt_bn128_G1 &other) const; + + alt_bn128_G1 operator+(const alt_bn128_G1 &other) const; + alt_bn128_G1 operator-() const; + alt_bn128_G1 operator-(const alt_bn128_G1 &other) const; + + alt_bn128_G1 add(const alt_bn128_G1 &other) const; + alt_bn128_G1 mixed_add(const alt_bn128_G1 &other) const; + alt_bn128_G1 dbl() const; + + bool is_well_formed() const; + + static alt_bn128_G1 zero(); + static alt_bn128_G1 one(); + static alt_bn128_G1 random_element(); + + static size_t size_in_bits() { return base_field::size_in_bits() + 1; } + static bigint base_field_char() { return base_field::field_char(); } + static bigint order() { return scalar_field::field_char(); } + + friend std::ostream& operator<<(std::ostream &out, const alt_bn128_G1 &g); + friend std::istream& operator>>(std::istream &in, alt_bn128_G1 &g); +}; + +template +alt_bn128_G1 operator*(const bigint &lhs, const alt_bn128_G1 &rhs) +{ + return scalar_mul(rhs, lhs); +} + +template& modulus_p> +alt_bn128_G1 operator*(const Fp_model &lhs, const alt_bn128_G1 &rhs) +{ + return scalar_mul(rhs, lhs.as_bigint()); +} + +std::ostream& operator<<(std::ostream& out, const std::vector &v); +std::istream& operator>>(std::istream& in, std::vector &v); + +template +void batch_to_special_all_non_zeros(std::vector &vec); +template<> +void batch_to_special_all_non_zeros(std::vector &vec); + +} // libsnark +#endif // ALT_BN128_G1_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/alt_bn128/alt_bn128_g2.cpp b/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/alt_bn128/alt_bn128_g2.cpp new file mode 100644 index 0000000..c4152e4 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/alt_bn128/alt_bn128_g2.cpp @@ -0,0 +1,505 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include "algebra/curves/alt_bn128/alt_bn128_g2.hpp" + +namespace libsnark { + +#ifdef PROFILE_OP_COUNTS +long long alt_bn128_G2::add_cnt = 0; +long long alt_bn128_G2::dbl_cnt = 0; +#endif + +std::vector alt_bn128_G2::wnaf_window_table; +std::vector alt_bn128_G2::fixed_base_exp_window_table; +alt_bn128_G2 alt_bn128_G2::G2_zero; +alt_bn128_G2 alt_bn128_G2::G2_one; + +alt_bn128_G2::alt_bn128_G2() +{ + this->X = G2_zero.X; + this->Y = G2_zero.Y; + this->Z = G2_zero.Z; +} + +alt_bn128_Fq2 alt_bn128_G2::mul_by_b(const alt_bn128_Fq2 &elt) +{ + return alt_bn128_Fq2(alt_bn128_twist_mul_by_b_c0 * elt.c0, alt_bn128_twist_mul_by_b_c1 * elt.c1); +} + +void alt_bn128_G2::print() const +{ + if (this->is_zero()) + { + printf("O\n"); + } + else + { + alt_bn128_G2 copy(*this); + copy.to_affine_coordinates(); + gmp_printf("(%Nd*z + %Nd , %Nd*z + %Nd)\n", + copy.X.c1.as_bigint().data, alt_bn128_Fq::num_limbs, + copy.X.c0.as_bigint().data, alt_bn128_Fq::num_limbs, + copy.Y.c1.as_bigint().data, alt_bn128_Fq::num_limbs, + copy.Y.c0.as_bigint().data, alt_bn128_Fq::num_limbs); + } +} + +void alt_bn128_G2::print_coordinates() const +{ + if (this->is_zero()) + { + printf("O\n"); + } + else + { + gmp_printf("(%Nd*z + %Nd : %Nd*z + %Nd : %Nd*z + %Nd)\n", + this->X.c1.as_bigint().data, alt_bn128_Fq::num_limbs, + this->X.c0.as_bigint().data, alt_bn128_Fq::num_limbs, + this->Y.c1.as_bigint().data, alt_bn128_Fq::num_limbs, + this->Y.c0.as_bigint().data, alt_bn128_Fq::num_limbs, + this->Z.c1.as_bigint().data, alt_bn128_Fq::num_limbs, + this->Z.c0.as_bigint().data, alt_bn128_Fq::num_limbs); + } +} + +void alt_bn128_G2::to_affine_coordinates() +{ + if (this->is_zero()) + { + this->X = alt_bn128_Fq2::zero(); + this->Y = alt_bn128_Fq2::one(); + this->Z = alt_bn128_Fq2::zero(); + } + else + { + alt_bn128_Fq2 Z_inv = Z.inverse(); + alt_bn128_Fq2 Z2_inv = Z_inv.squared(); + alt_bn128_Fq2 Z3_inv = Z2_inv * Z_inv; + this->X = this->X * Z2_inv; + this->Y = this->Y * Z3_inv; + this->Z = alt_bn128_Fq2::one(); + } +} + +void alt_bn128_G2::to_special() +{ + this->to_affine_coordinates(); +} + +bool alt_bn128_G2::is_special() const +{ + return (this->is_zero() || this->Z == alt_bn128_Fq2::one()); +} + +bool alt_bn128_G2::is_zero() const +{ + return (this->Z.is_zero()); +} + +bool alt_bn128_G2::operator==(const alt_bn128_G2 &other) const +{ + if (this->is_zero()) + { + return other.is_zero(); + } + + if (other.is_zero()) + { + return false; + } + + /* now neither is O */ + + // using Jacobian coordinates so: + // (X1:Y1:Z1) = (X2:Y2:Z2) + // iff + // X1/Z1^2 == X2/Z2^2 and Y1/Z1^3 == Y2/Z2^3 + // iff + // X1 * Z2^2 == X2 * Z1^2 and Y1 * Z2^3 == Y2 * Z1^3 + + alt_bn128_Fq2 Z1_squared = (this->Z).squared(); + alt_bn128_Fq2 Z2_squared = (other.Z).squared(); + + if ((this->X * Z2_squared) != (other.X * Z1_squared)) + { + return false; + } + + alt_bn128_Fq2 Z1_cubed = (this->Z) * Z1_squared; + alt_bn128_Fq2 Z2_cubed = (other.Z) * Z2_squared; + + if ((this->Y * Z2_cubed) != (other.Y * Z1_cubed)) + { + return false; + } + + return true; +} + +bool alt_bn128_G2::operator!=(const alt_bn128_G2& other) const +{ + return !(operator==(other)); +} + +alt_bn128_G2 alt_bn128_G2::operator+(const alt_bn128_G2 &other) const +{ + // handle special cases having to do with O + if (this->is_zero()) + { + return other; + } + + if (other.is_zero()) + { + return *this; + } + + // no need to handle points of order 2,4 + // (they cannot exist in a prime-order subgroup) + + // check for doubling case + + // using Jacobian coordinates so: + // (X1:Y1:Z1) = (X2:Y2:Z2) + // iff + // X1/Z1^2 == X2/Z2^2 and Y1/Z1^3 == Y2/Z2^3 + // iff + // X1 * Z2^2 == X2 * Z1^2 and Y1 * Z2^3 == Y2 * Z1^3 + + alt_bn128_Fq2 Z1Z1 = (this->Z).squared(); + alt_bn128_Fq2 Z2Z2 = (other.Z).squared(); + + alt_bn128_Fq2 U1 = this->X * Z2Z2; + alt_bn128_Fq2 U2 = other.X * Z1Z1; + + alt_bn128_Fq2 Z1_cubed = (this->Z) * Z1Z1; + alt_bn128_Fq2 Z2_cubed = (other.Z) * Z2Z2; + + alt_bn128_Fq2 S1 = (this->Y) * Z2_cubed; // S1 = Y1 * Z2 * Z2Z2 + alt_bn128_Fq2 S2 = (other.Y) * Z1_cubed; // S2 = Y2 * Z1 * Z1Z1 + + if (U1 == U2 && S1 == S2) + { + // dbl case; nothing of above can be reused + return this->dbl(); + } + + // rest of add case + alt_bn128_Fq2 H = U2 - U1; // H = U2-U1 + alt_bn128_Fq2 S2_minus_S1 = S2-S1; + alt_bn128_Fq2 I = (H+H).squared(); // I = (2 * H)^2 + alt_bn128_Fq2 J = H * I; // J = H * I + alt_bn128_Fq2 r = S2_minus_S1 + S2_minus_S1; // r = 2 * (S2-S1) + alt_bn128_Fq2 V = U1 * I; // V = U1 * I + alt_bn128_Fq2 X3 = r.squared() - J - (V+V); // X3 = r^2 - J - 2 * V + alt_bn128_Fq2 S1_J = S1 * J; + alt_bn128_Fq2 Y3 = r * (V-X3) - (S1_J+S1_J); // Y3 = r * (V-X3)-2 S1 J + alt_bn128_Fq2 Z3 = ((this->Z+other.Z).squared()-Z1Z1-Z2Z2) * H; // Z3 = ((Z1+Z2)^2-Z1Z1-Z2Z2) * H + + return alt_bn128_G2(X3, Y3, Z3); +} + +alt_bn128_G2 alt_bn128_G2::operator-() const +{ + return alt_bn128_G2(this->X, -(this->Y), this->Z); +} + + +alt_bn128_G2 alt_bn128_G2::operator-(const alt_bn128_G2 &other) const +{ + return (*this) + (-other); +} + +alt_bn128_G2 alt_bn128_G2::add(const alt_bn128_G2 &other) const +{ + // handle special cases having to do with O + if (this->is_zero()) + { + return other; + } + + if (other.is_zero()) + { + return *this; + } + + // no need to handle points of order 2,4 + // (they cannot exist in a prime-order subgroup) + + // handle double case + if (this->operator==(other)) + { + return this->dbl(); + } + +#ifdef PROFILE_OP_COUNTS + this->add_cnt++; +#endif + // NOTE: does not handle O and pts of order 2,4 + // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-projective.html#addition-add-1998-cmo-2 + + alt_bn128_Fq2 Z1Z1 = (this->Z).squared(); // Z1Z1 = Z1^2 + alt_bn128_Fq2 Z2Z2 = (other.Z).squared(); // Z2Z2 = Z2^2 + alt_bn128_Fq2 U1 = (this->X) * Z2Z2; // U1 = X1 * Z2Z2 + alt_bn128_Fq2 U2 = (other.X) * Z1Z1; // U2 = X2 * Z1Z1 + alt_bn128_Fq2 S1 = (this->Y) * (other.Z) * Z2Z2; // S1 = Y1 * Z2 * Z2Z2 + alt_bn128_Fq2 S2 = (other.Y) * (this->Z) * Z1Z1; // S2 = Y2 * Z1 * Z1Z1 + alt_bn128_Fq2 H = U2 - U1; // H = U2-U1 + alt_bn128_Fq2 S2_minus_S1 = S2-S1; + alt_bn128_Fq2 I = (H+H).squared(); // I = (2 * H)^2 + alt_bn128_Fq2 J = H * I; // J = H * I + alt_bn128_Fq2 r = S2_minus_S1 + S2_minus_S1; // r = 2 * (S2-S1) + alt_bn128_Fq2 V = U1 * I; // V = U1 * I + alt_bn128_Fq2 X3 = r.squared() - J - (V+V); // X3 = r^2 - J - 2 * V + alt_bn128_Fq2 S1_J = S1 * J; + alt_bn128_Fq2 Y3 = r * (V-X3) - (S1_J+S1_J); // Y3 = r * (V-X3)-2 S1 J + alt_bn128_Fq2 Z3 = ((this->Z+other.Z).squared()-Z1Z1-Z2Z2) * H; // Z3 = ((Z1+Z2)^2-Z1Z1-Z2Z2) * H + + return alt_bn128_G2(X3, Y3, Z3); +} + +alt_bn128_G2 alt_bn128_G2::mixed_add(const alt_bn128_G2 &other) const +{ +#ifdef DEBUG + assert(other.is_special()); +#endif + + // handle special cases having to do with O + if (this->is_zero()) + { + return other; + } + + if (other.is_zero()) + { + return *this; + } + + // no need to handle points of order 2,4 + // (they cannot exist in a prime-order subgroup) + + // check for doubling case + + // using Jacobian coordinates so: + // (X1:Y1:Z1) = (X2:Y2:Z2) + // iff + // X1/Z1^2 == X2/Z2^2 and Y1/Z1^3 == Y2/Z2^3 + // iff + // X1 * Z2^2 == X2 * Z1^2 and Y1 * Z2^3 == Y2 * Z1^3 + + // we know that Z2 = 1 + + const alt_bn128_Fq2 Z1Z1 = (this->Z).squared(); + + const alt_bn128_Fq2 &U1 = this->X; + const alt_bn128_Fq2 U2 = other.X * Z1Z1; + + const alt_bn128_Fq2 Z1_cubed = (this->Z) * Z1Z1; + + const alt_bn128_Fq2 &S1 = (this->Y); // S1 = Y1 * Z2 * Z2Z2 + const alt_bn128_Fq2 S2 = (other.Y) * Z1_cubed; // S2 = Y2 * Z1 * Z1Z1 + + if (U1 == U2 && S1 == S2) + { + // dbl case; nothing of above can be reused + return this->dbl(); + } + +#ifdef PROFILE_OP_COUNTS + this->add_cnt++; +#endif + + // NOTE: does not handle O and pts of order 2,4 + // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-madd-2007-bl + alt_bn128_Fq2 H = U2-(this->X); // H = U2-X1 + alt_bn128_Fq2 HH = H.squared() ; // HH = H&2 + alt_bn128_Fq2 I = HH+HH; // I = 4*HH + I = I + I; + alt_bn128_Fq2 J = H*I; // J = H*I + alt_bn128_Fq2 r = S2-(this->Y); // r = 2*(S2-Y1) + r = r + r; + alt_bn128_Fq2 V = (this->X) * I ; // V = X1*I + alt_bn128_Fq2 X3 = r.squared()-J-V-V; // X3 = r^2-J-2*V + alt_bn128_Fq2 Y3 = (this->Y)*J; // Y3 = r*(V-X3)-2*Y1*J + Y3 = r*(V-X3) - Y3 - Y3; + alt_bn128_Fq2 Z3 = ((this->Z)+H).squared() - Z1Z1 - HH; // Z3 = (Z1+H)^2-Z1Z1-HH + + return alt_bn128_G2(X3, Y3, Z3); +} + +alt_bn128_G2 alt_bn128_G2::dbl() const +{ +#ifdef PROFILE_OP_COUNTS + this->dbl_cnt++; +#endif + // handle point at infinity + if (this->is_zero()) + { + return (*this); + } + + // NOTE: does not handle O and pts of order 2,4 + // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-projective.html#doubling-dbl-2007-bl + + alt_bn128_Fq2 A = (this->X).squared(); // A = X1^2 + alt_bn128_Fq2 B = (this->Y).squared(); // B = Y1^2 + alt_bn128_Fq2 C = B.squared(); // C = B^2 + alt_bn128_Fq2 D = (this->X + B).squared() - A - C; + D = D+D; // D = 2 * ((X1 + B)^2 - A - C) + alt_bn128_Fq2 E = A + A + A; // E = 3 * A + alt_bn128_Fq2 F = E.squared(); // F = E^2 + alt_bn128_Fq2 X3 = F - (D+D); // X3 = F - 2 D + alt_bn128_Fq2 eightC = C+C; + eightC = eightC + eightC; + eightC = eightC + eightC; + alt_bn128_Fq2 Y3 = E * (D - X3) - eightC; // Y3 = E * (D - X3) - 8 * C + alt_bn128_Fq2 Y1Z1 = (this->Y)*(this->Z); + alt_bn128_Fq2 Z3 = Y1Z1 + Y1Z1; // Z3 = 2 * Y1 * Z1 + + return alt_bn128_G2(X3, Y3, Z3); +} + +alt_bn128_G2 alt_bn128_G2::mul_by_q() const +{ + return alt_bn128_G2(alt_bn128_twist_mul_by_q_X * (this->X).Frobenius_map(1), + alt_bn128_twist_mul_by_q_Y * (this->Y).Frobenius_map(1), + (this->Z).Frobenius_map(1)); +} + +bool alt_bn128_G2::is_well_formed() const +{ + if (this->is_zero()) + { + return true; + } + else + { + /* + y^2 = x^3 + b + + We are using Jacobian coordinates, so equation we need to check is actually + + (y/z^3)^2 = (x/z^2)^3 + b + y^2 / z^6 = x^3 / z^6 + b + y^2 = x^3 + b z^6 + */ + alt_bn128_Fq2 X2 = this->X.squared(); + alt_bn128_Fq2 Y2 = this->Y.squared(); + alt_bn128_Fq2 Z2 = this->Z.squared(); + + alt_bn128_Fq2 X3 = this->X * X2; + alt_bn128_Fq2 Z3 = this->Z * Z2; + alt_bn128_Fq2 Z6 = Z3.squared(); + + return (Y2 == X3 + alt_bn128_twist_coeff_b * Z6); + } +} + +alt_bn128_G2 alt_bn128_G2::zero() +{ + return G2_zero; +} + +alt_bn128_G2 alt_bn128_G2::one() +{ + return G2_one; +} + +alt_bn128_G2 alt_bn128_G2::random_element() +{ + return (alt_bn128_Fr::random_element().as_bigint()) * G2_one; +} + +std::ostream& operator<<(std::ostream &out, const alt_bn128_G2 &g) +{ + alt_bn128_G2 copy(g); + copy.to_affine_coordinates(); + out << (copy.is_zero() ? 1 : 0) << OUTPUT_SEPARATOR; +#ifdef NO_PT_COMPRESSION + out << copy.X << OUTPUT_SEPARATOR << copy.Y; +#else + /* storing LSB of Y */ + out << copy.X << OUTPUT_SEPARATOR << (copy.Y.c0.as_bigint().data[0] & 1); +#endif + + return out; +} + +std::istream& operator>>(std::istream &in, alt_bn128_G2 &g) +{ + char is_zero; + alt_bn128_Fq2 tX, tY; + +#ifdef NO_PT_COMPRESSION + in >> is_zero >> tX >> tY; + is_zero -= '0'; +#else + in.read((char*)&is_zero, 1); // this reads is_zero; + is_zero -= '0'; + consume_OUTPUT_SEPARATOR(in); + + unsigned char Y_lsb; + in >> tX; + consume_OUTPUT_SEPARATOR(in); + in.read((char*)&Y_lsb, 1); + Y_lsb -= '0'; + + // y = +/- sqrt(x^3 + b) + if (!is_zero) + { + alt_bn128_Fq2 tX2 = tX.squared(); + alt_bn128_Fq2 tY2 = tX2 * tX + alt_bn128_twist_coeff_b; + tY = tY2.sqrt(); + + if ((tY.c0.as_bigint().data[0] & 1) != Y_lsb) + { + tY = -tY; + } + } +#endif + // using projective coordinates + if (!is_zero) + { + g.X = tX; + g.Y = tY; + g.Z = alt_bn128_Fq2::one(); + } + else + { + g = alt_bn128_G2::zero(); + } + + return in; +} + +template<> +void batch_to_special_all_non_zeros(std::vector &vec) +{ + std::vector Z_vec; + Z_vec.reserve(vec.size()); + + for (auto &el: vec) + { + Z_vec.emplace_back(el.Z); + } + batch_invert(Z_vec); + + const alt_bn128_Fq2 one = alt_bn128_Fq2::one(); + + for (size_t i = 0; i < vec.size(); ++i) + { + alt_bn128_Fq2 Z2 = Z_vec[i].squared(); + alt_bn128_Fq2 Z3 = Z_vec[i] * Z2; + + vec[i].X = vec[i].X * Z2; + vec[i].Y = vec[i].Y * Z3; + vec[i].Z = one; + } +} + +} // libsnark diff --git a/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/alt_bn128/alt_bn128_g2.hpp b/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/alt_bn128/alt_bn128_g2.hpp new file mode 100644 index 0000000..a996a2d --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/alt_bn128/alt_bn128_g2.hpp @@ -0,0 +1,96 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef ALT_BN128_G2_HPP_ +#define ALT_BN128_G2_HPP_ +#include +#include "algebra/curves/alt_bn128/alt_bn128_init.hpp" +#include "algebra/curves/curve_utils.hpp" + +namespace libsnark { + +class alt_bn128_G2; +std::ostream& operator<<(std::ostream &, const alt_bn128_G2&); +std::istream& operator>>(std::istream &, alt_bn128_G2&); + +class alt_bn128_G2 { +public: +#ifdef PROFILE_OP_COUNTS + static long long add_cnt; + static long long dbl_cnt; +#endif + static std::vector wnaf_window_table; + static std::vector fixed_base_exp_window_table; + static alt_bn128_G2 G2_zero; + static alt_bn128_G2 G2_one; + + typedef alt_bn128_Fq base_field; + typedef alt_bn128_Fq2 twist_field; + typedef alt_bn128_Fr scalar_field; + + alt_bn128_Fq2 X, Y, Z; + + // using Jacobian coordinates + alt_bn128_G2(); + alt_bn128_G2(const alt_bn128_Fq2& X, const alt_bn128_Fq2& Y, const alt_bn128_Fq2& Z) : X(X), Y(Y), Z(Z) {}; + + static alt_bn128_Fq2 mul_by_b(const alt_bn128_Fq2 &elt); + + void print() const; + void print_coordinates() const; + + void to_affine_coordinates(); + void to_special(); + bool is_special() const; + + bool is_zero() const; + + bool operator==(const alt_bn128_G2 &other) const; + bool operator!=(const alt_bn128_G2 &other) const; + + alt_bn128_G2 operator+(const alt_bn128_G2 &other) const; + alt_bn128_G2 operator-() const; + alt_bn128_G2 operator-(const alt_bn128_G2 &other) const; + + alt_bn128_G2 add(const alt_bn128_G2 &other) const; + alt_bn128_G2 mixed_add(const alt_bn128_G2 &other) const; + alt_bn128_G2 dbl() const; + alt_bn128_G2 mul_by_q() const; + + bool is_well_formed() const; + + static alt_bn128_G2 zero(); + static alt_bn128_G2 one(); + static alt_bn128_G2 random_element(); + + static size_t size_in_bits() { return twist_field::size_in_bits() + 1; } + static bigint base_field_char() { return base_field::field_char(); } + static bigint order() { return scalar_field::field_char(); } + + friend std::ostream& operator<<(std::ostream &out, const alt_bn128_G2 &g); + friend std::istream& operator>>(std::istream &in, alt_bn128_G2 &g); +}; + +template +alt_bn128_G2 operator*(const bigint &lhs, const alt_bn128_G2 &rhs) +{ + return scalar_mul(rhs, lhs); +} + +template& modulus_p> +alt_bn128_G2 operator*(const Fp_model &lhs, const alt_bn128_G2 &rhs) +{ + return scalar_mul(rhs, lhs.as_bigint()); +} + +template +void batch_to_special_all_non_zeros(std::vector &vec); +template<> +void batch_to_special_all_non_zeros(std::vector &vec); + +} // libsnark +#endif // ALT_BN128_G2_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/alt_bn128/alt_bn128_init.cpp b/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/alt_bn128/alt_bn128_init.cpp new file mode 100644 index 0000000..7c23773 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/alt_bn128/alt_bn128_init.cpp @@ -0,0 +1,273 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include "algebra/curves/alt_bn128/alt_bn128_init.hpp" +#include "algebra/curves/alt_bn128/alt_bn128_g1.hpp" +#include "algebra/curves/alt_bn128/alt_bn128_g2.hpp" + +namespace libsnark { + +bigint alt_bn128_modulus_r; +bigint alt_bn128_modulus_q; + +alt_bn128_Fq alt_bn128_coeff_b; +alt_bn128_Fq2 alt_bn128_twist; +alt_bn128_Fq2 alt_bn128_twist_coeff_b; +alt_bn128_Fq alt_bn128_twist_mul_by_b_c0; +alt_bn128_Fq alt_bn128_twist_mul_by_b_c1; +alt_bn128_Fq2 alt_bn128_twist_mul_by_q_X; +alt_bn128_Fq2 alt_bn128_twist_mul_by_q_Y; + +bigint alt_bn128_ate_loop_count; +bool alt_bn128_ate_is_loop_count_neg; +bigint<12*alt_bn128_q_limbs> alt_bn128_final_exponent; +bigint alt_bn128_final_exponent_z; +bool alt_bn128_final_exponent_is_z_neg; + +void init_alt_bn128_params() +{ + typedef bigint bigint_r; + typedef bigint bigint_q; + + assert(sizeof(mp_limb_t) == 8 || sizeof(mp_limb_t) == 4); // Montgomery assumes this + + /* parameters for scalar field Fr */ + + alt_bn128_modulus_r = bigint_r("21888242871839275222246405745257275088548364400416034343698204186575808495617"); + assert(alt_bn128_Fr::modulus_is_valid()); + if (sizeof(mp_limb_t) == 8) + { + alt_bn128_Fr::Rsquared = bigint_r("944936681149208446651664254269745548490766851729442924617792859073125903783"); + alt_bn128_Fr::Rcubed = bigint_r("5866548545943845227489894872040244720403868105578784105281690076696998248512"); + alt_bn128_Fr::inv = 0xc2e1f593efffffff; + } + if (sizeof(mp_limb_t) == 4) + { + alt_bn128_Fr::Rsquared = bigint_r("944936681149208446651664254269745548490766851729442924617792859073125903783"); + alt_bn128_Fr::Rcubed = bigint_r("5866548545943845227489894872040244720403868105578784105281690076696998248512"); + alt_bn128_Fr::inv = 0xefffffff; + } + alt_bn128_Fr::num_bits = 254; + alt_bn128_Fr::euler = bigint_r("10944121435919637611123202872628637544274182200208017171849102093287904247808"); + alt_bn128_Fr::s = 28; + alt_bn128_Fr::t = bigint_r("81540058820840996586704275553141814055101440848469862132140264610111"); + alt_bn128_Fr::t_minus_1_over_2 = bigint_r("40770029410420498293352137776570907027550720424234931066070132305055"); + alt_bn128_Fr::multiplicative_generator = alt_bn128_Fr("5"); + alt_bn128_Fr::root_of_unity = alt_bn128_Fr("19103219067921713944291392827692070036145651957329286315305642004821462161904"); + alt_bn128_Fr::nqr = alt_bn128_Fr("5"); + alt_bn128_Fr::nqr_to_t = alt_bn128_Fr("19103219067921713944291392827692070036145651957329286315305642004821462161904"); + + /* parameters for base field Fq */ + + alt_bn128_modulus_q = bigint_q("21888242871839275222246405745257275088696311157297823662689037894645226208583"); + assert(alt_bn128_Fq::modulus_is_valid()); + if (sizeof(mp_limb_t) == 8) + { + alt_bn128_Fq::Rsquared = bigint_q("3096616502983703923843567936837374451735540968419076528771170197431451843209"); + alt_bn128_Fq::Rcubed = bigint_q("14921786541159648185948152738563080959093619838510245177710943249661917737183"); + alt_bn128_Fq::inv = 0x87d20782e4866389; + } + if (sizeof(mp_limb_t) == 4) + { + alt_bn128_Fq::Rsquared = bigint_q("3096616502983703923843567936837374451735540968419076528771170197431451843209"); + alt_bn128_Fq::Rcubed = bigint_q("14921786541159648185948152738563080959093619838510245177710943249661917737183"); + alt_bn128_Fq::inv = 0xe4866389; + } + alt_bn128_Fq::num_bits = 254; + alt_bn128_Fq::euler = bigint_q("10944121435919637611123202872628637544348155578648911831344518947322613104291"); + alt_bn128_Fq::s = 1; + alt_bn128_Fq::t = bigint_q("10944121435919637611123202872628637544348155578648911831344518947322613104291"); + alt_bn128_Fq::t_minus_1_over_2 = bigint_q("5472060717959818805561601436314318772174077789324455915672259473661306552145"); + alt_bn128_Fq::multiplicative_generator = alt_bn128_Fq("3"); + alt_bn128_Fq::root_of_unity = alt_bn128_Fq("21888242871839275222246405745257275088696311157297823662689037894645226208582"); + alt_bn128_Fq::nqr = alt_bn128_Fq("3"); + alt_bn128_Fq::nqr_to_t = alt_bn128_Fq("21888242871839275222246405745257275088696311157297823662689037894645226208582"); + + /* parameters for twist field Fq2 */ + alt_bn128_Fq2::euler = bigint<2*alt_bn128_q_limbs>("239547588008311421220994022608339370399626158265550411218223901127035046843189118723920525909718935985594116157406550130918127817069793474323196511433944"); + alt_bn128_Fq2::s = 4; + alt_bn128_Fq2::t = bigint<2*alt_bn128_q_limbs>("29943448501038927652624252826042421299953269783193801402277987640879380855398639840490065738714866998199264519675818766364765977133724184290399563929243"); + alt_bn128_Fq2::t_minus_1_over_2 = bigint<2*alt_bn128_q_limbs>("14971724250519463826312126413021210649976634891596900701138993820439690427699319920245032869357433499099632259837909383182382988566862092145199781964621"); + alt_bn128_Fq2::non_residue = alt_bn128_Fq("21888242871839275222246405745257275088696311157297823662689037894645226208582"); + alt_bn128_Fq2::nqr = alt_bn128_Fq2(alt_bn128_Fq("2"),alt_bn128_Fq("1")); + alt_bn128_Fq2::nqr_to_t = alt_bn128_Fq2(alt_bn128_Fq("5033503716262624267312492558379982687175200734934877598599011485707452665730"),alt_bn128_Fq("314498342015008975724433667930697407966947188435857772134235984660852259084")); + alt_bn128_Fq2::Frobenius_coeffs_c1[0] = alt_bn128_Fq("1"); + alt_bn128_Fq2::Frobenius_coeffs_c1[1] = alt_bn128_Fq("21888242871839275222246405745257275088696311157297823662689037894645226208582"); + + /* parameters for Fq6 */ + alt_bn128_Fq6::non_residue = alt_bn128_Fq2(alt_bn128_Fq("9"),alt_bn128_Fq("1")); + alt_bn128_Fq6::Frobenius_coeffs_c1[0] = alt_bn128_Fq2(alt_bn128_Fq("1"),alt_bn128_Fq("0")); + alt_bn128_Fq6::Frobenius_coeffs_c1[1] = alt_bn128_Fq2(alt_bn128_Fq("21575463638280843010398324269430826099269044274347216827212613867836435027261"),alt_bn128_Fq("10307601595873709700152284273816112264069230130616436755625194854815875713954")); + alt_bn128_Fq6::Frobenius_coeffs_c1[2] = alt_bn128_Fq2(alt_bn128_Fq("21888242871839275220042445260109153167277707414472061641714758635765020556616"),alt_bn128_Fq("0")); + alt_bn128_Fq6::Frobenius_coeffs_c1[3] = alt_bn128_Fq2(alt_bn128_Fq("3772000881919853776433695186713858239009073593817195771773381919316419345261"),alt_bn128_Fq("2236595495967245188281701248203181795121068902605861227855261137820944008926")); + alt_bn128_Fq6::Frobenius_coeffs_c1[4] = alt_bn128_Fq2(alt_bn128_Fq("2203960485148121921418603742825762020974279258880205651966"),alt_bn128_Fq("0")); + alt_bn128_Fq6::Frobenius_coeffs_c1[5] = alt_bn128_Fq2(alt_bn128_Fq("18429021223477853657660792034369865839114504446431234726392080002137598044644"),alt_bn128_Fq("9344045779998320333812420223237981029506012124075525679208581902008406485703")); + alt_bn128_Fq6::Frobenius_coeffs_c2[0] = alt_bn128_Fq2(alt_bn128_Fq("1"),alt_bn128_Fq("0")); + alt_bn128_Fq6::Frobenius_coeffs_c2[1] = alt_bn128_Fq2(alt_bn128_Fq("2581911344467009335267311115468803099551665605076196740867805258568234346338"),alt_bn128_Fq("19937756971775647987995932169929341994314640652964949448313374472400716661030")); + alt_bn128_Fq6::Frobenius_coeffs_c2[2] = alt_bn128_Fq2(alt_bn128_Fq("2203960485148121921418603742825762020974279258880205651966"),alt_bn128_Fq("0")); + alt_bn128_Fq6::Frobenius_coeffs_c2[3] = alt_bn128_Fq2(alt_bn128_Fq("5324479202449903542726783395506214481928257762400643279780343368557297135718"),alt_bn128_Fq("16208900380737693084919495127334387981393726419856888799917914180988844123039")); + alt_bn128_Fq6::Frobenius_coeffs_c2[4] = alt_bn128_Fq2(alt_bn128_Fq("21888242871839275220042445260109153167277707414472061641714758635765020556616"),alt_bn128_Fq("0")); + alt_bn128_Fq6::Frobenius_coeffs_c2[5] = alt_bn128_Fq2(alt_bn128_Fq("13981852324922362344252311234282257507216387789820983642040889267519694726527"),alt_bn128_Fq("7629828391165209371577384193250820201684255241773809077146787135900891633097")); + + /* parameters for Fq12 */ + + alt_bn128_Fq12::non_residue = alt_bn128_Fq2(alt_bn128_Fq("9"),alt_bn128_Fq("1")); + alt_bn128_Fq12::Frobenius_coeffs_c1[0] = alt_bn128_Fq2(alt_bn128_Fq("1"),alt_bn128_Fq("0")); + alt_bn128_Fq12::Frobenius_coeffs_c1[1] = alt_bn128_Fq2(alt_bn128_Fq("8376118865763821496583973867626364092589906065868298776909617916018768340080"),alt_bn128_Fq("16469823323077808223889137241176536799009286646108169935659301613961712198316")); + alt_bn128_Fq12::Frobenius_coeffs_c1[2] = alt_bn128_Fq2(alt_bn128_Fq("21888242871839275220042445260109153167277707414472061641714758635765020556617"),alt_bn128_Fq("0")); + alt_bn128_Fq12::Frobenius_coeffs_c1[3] = alt_bn128_Fq2(alt_bn128_Fq("11697423496358154304825782922584725312912383441159505038794027105778954184319"),alt_bn128_Fq("303847389135065887422783454877609941456349188919719272345083954437860409601")); + alt_bn128_Fq12::Frobenius_coeffs_c1[4] = alt_bn128_Fq2(alt_bn128_Fq("21888242871839275220042445260109153167277707414472061641714758635765020556616"),alt_bn128_Fq("0")); + alt_bn128_Fq12::Frobenius_coeffs_c1[5] = alt_bn128_Fq2(alt_bn128_Fq("3321304630594332808241809054958361220322477375291206261884409189760185844239"),alt_bn128_Fq("5722266937896532885780051958958348231143373700109372999374820235121374419868")); + alt_bn128_Fq12::Frobenius_coeffs_c1[6] = alt_bn128_Fq2(alt_bn128_Fq("21888242871839275222246405745257275088696311157297823662689037894645226208582"),alt_bn128_Fq("0")); + alt_bn128_Fq12::Frobenius_coeffs_c1[7] = alt_bn128_Fq2(alt_bn128_Fq("13512124006075453725662431877630910996106405091429524885779419978626457868503"),alt_bn128_Fq("5418419548761466998357268504080738289687024511189653727029736280683514010267")); + alt_bn128_Fq12::Frobenius_coeffs_c1[8] = alt_bn128_Fq2(alt_bn128_Fq("2203960485148121921418603742825762020974279258880205651966"),alt_bn128_Fq("0")); + alt_bn128_Fq12::Frobenius_coeffs_c1[9] = alt_bn128_Fq2(alt_bn128_Fq("10190819375481120917420622822672549775783927716138318623895010788866272024264"),alt_bn128_Fq("21584395482704209334823622290379665147239961968378104390343953940207365798982")); + alt_bn128_Fq12::Frobenius_coeffs_c1[10] = alt_bn128_Fq2(alt_bn128_Fq("2203960485148121921418603742825762020974279258880205651967"),alt_bn128_Fq("0")); + alt_bn128_Fq12::Frobenius_coeffs_c1[11] = alt_bn128_Fq2(alt_bn128_Fq("18566938241244942414004596690298913868373833782006617400804628704885040364344"),alt_bn128_Fq("16165975933942742336466353786298926857552937457188450663314217659523851788715")); + + /* choice of short Weierstrass curve and its twist */ + + alt_bn128_coeff_b = alt_bn128_Fq("3"); + alt_bn128_twist = alt_bn128_Fq2(alt_bn128_Fq("9"), alt_bn128_Fq("1")); + alt_bn128_twist_coeff_b = alt_bn128_coeff_b * alt_bn128_twist.inverse(); + alt_bn128_twist_mul_by_b_c0 = alt_bn128_coeff_b * alt_bn128_Fq2::non_residue; + alt_bn128_twist_mul_by_b_c1 = alt_bn128_coeff_b * alt_bn128_Fq2::non_residue; + alt_bn128_twist_mul_by_q_X = alt_bn128_Fq2(alt_bn128_Fq("21575463638280843010398324269430826099269044274347216827212613867836435027261"), + alt_bn128_Fq("10307601595873709700152284273816112264069230130616436755625194854815875713954")); + alt_bn128_twist_mul_by_q_Y = alt_bn128_Fq2(alt_bn128_Fq("2821565182194536844548159561693502659359617185244120367078079554186484126554"), + alt_bn128_Fq("3505843767911556378687030309984248845540243509899259641013678093033130930403")); + + /* choice of group G1 */ + alt_bn128_G1::G1_zero = alt_bn128_G1(alt_bn128_Fq::zero(), + alt_bn128_Fq::one(), + alt_bn128_Fq::zero()); + alt_bn128_G1::G1_one = alt_bn128_G1(alt_bn128_Fq("1"), + alt_bn128_Fq("2"), + alt_bn128_Fq::one()); + alt_bn128_G1::wnaf_window_table.push_back(11); + alt_bn128_G1::wnaf_window_table.push_back(24); + alt_bn128_G1::wnaf_window_table.push_back(60); + alt_bn128_G1::wnaf_window_table.push_back(127); + + alt_bn128_G1::fixed_base_exp_window_table.resize(0); + // window 1 is unbeaten in [-inf, 4.99] + alt_bn128_G1::fixed_base_exp_window_table.push_back(1); + // window 2 is unbeaten in [4.99, 10.99] + alt_bn128_G1::fixed_base_exp_window_table.push_back(5); + // window 3 is unbeaten in [10.99, 32.29] + alt_bn128_G1::fixed_base_exp_window_table.push_back(11); + // window 4 is unbeaten in [32.29, 55.23] + alt_bn128_G1::fixed_base_exp_window_table.push_back(32); + // window 5 is unbeaten in [55.23, 162.03] + alt_bn128_G1::fixed_base_exp_window_table.push_back(55); + // window 6 is unbeaten in [162.03, 360.15] + alt_bn128_G1::fixed_base_exp_window_table.push_back(162); + // window 7 is unbeaten in [360.15, 815.44] + alt_bn128_G1::fixed_base_exp_window_table.push_back(360); + // window 8 is unbeaten in [815.44, 2373.07] + alt_bn128_G1::fixed_base_exp_window_table.push_back(815); + // window 9 is unbeaten in [2373.07, 6977.75] + alt_bn128_G1::fixed_base_exp_window_table.push_back(2373); + // window 10 is unbeaten in [6977.75, 7122.23] + alt_bn128_G1::fixed_base_exp_window_table.push_back(6978); + // window 11 is unbeaten in [7122.23, 57818.46] + alt_bn128_G1::fixed_base_exp_window_table.push_back(7122); + // window 12 is never the best + alt_bn128_G1::fixed_base_exp_window_table.push_back(0); + // window 13 is unbeaten in [57818.46, 169679.14] + alt_bn128_G1::fixed_base_exp_window_table.push_back(57818); + // window 14 is never the best + alt_bn128_G1::fixed_base_exp_window_table.push_back(0); + // window 15 is unbeaten in [169679.14, 439758.91] + alt_bn128_G1::fixed_base_exp_window_table.push_back(169679); + // window 16 is unbeaten in [439758.91, 936073.41] + alt_bn128_G1::fixed_base_exp_window_table.push_back(439759); + // window 17 is unbeaten in [936073.41, 4666554.74] + alt_bn128_G1::fixed_base_exp_window_table.push_back(936073); + // window 18 is never the best + alt_bn128_G1::fixed_base_exp_window_table.push_back(0); + // window 19 is unbeaten in [4666554.74, 7580404.42] + alt_bn128_G1::fixed_base_exp_window_table.push_back(4666555); + // window 20 is unbeaten in [7580404.42, 34552892.20] + alt_bn128_G1::fixed_base_exp_window_table.push_back(7580404); + // window 21 is never the best + alt_bn128_G1::fixed_base_exp_window_table.push_back(0); + // window 22 is unbeaten in [34552892.20, inf] + alt_bn128_G1::fixed_base_exp_window_table.push_back(34552892); + + /* choice of group G2 */ + + alt_bn128_G2::G2_zero = alt_bn128_G2(alt_bn128_Fq2::zero(), + alt_bn128_Fq2::one(), + alt_bn128_Fq2::zero()); + + alt_bn128_G2::G2_one = alt_bn128_G2(alt_bn128_Fq2(alt_bn128_Fq("10857046999023057135944570762232829481370756359578518086990519993285655852781"), + alt_bn128_Fq("11559732032986387107991004021392285783925812861821192530917403151452391805634")), + alt_bn128_Fq2(alt_bn128_Fq("8495653923123431417604973247489272438418190587263600148770280649306958101930"), + alt_bn128_Fq("4082367875863433681332203403145435568316851327593401208105741076214120093531")), + alt_bn128_Fq2::one()); + alt_bn128_G2::wnaf_window_table.push_back(5); + alt_bn128_G2::wnaf_window_table.push_back(15); + alt_bn128_G2::wnaf_window_table.push_back(39); + alt_bn128_G2::wnaf_window_table.push_back(109); + + alt_bn128_G2::fixed_base_exp_window_table.resize(0); + // window 1 is unbeaten in [-inf, 5.10] + alt_bn128_G2::fixed_base_exp_window_table.push_back(1); + // window 2 is unbeaten in [5.10, 10.43] + alt_bn128_G2::fixed_base_exp_window_table.push_back(5); + // window 3 is unbeaten in [10.43, 25.28] + alt_bn128_G2::fixed_base_exp_window_table.push_back(10); + // window 4 is unbeaten in [25.28, 59.00] + alt_bn128_G2::fixed_base_exp_window_table.push_back(25); + // window 5 is unbeaten in [59.00, 154.03] + alt_bn128_G2::fixed_base_exp_window_table.push_back(59); + // window 6 is unbeaten in [154.03, 334.25] + alt_bn128_G2::fixed_base_exp_window_table.push_back(154); + // window 7 is unbeaten in [334.25, 742.58] + alt_bn128_G2::fixed_base_exp_window_table.push_back(334); + // window 8 is unbeaten in [742.58, 2034.40] + alt_bn128_G2::fixed_base_exp_window_table.push_back(743); + // window 9 is unbeaten in [2034.40, 4987.56] + alt_bn128_G2::fixed_base_exp_window_table.push_back(2034); + // window 10 is unbeaten in [4987.56, 8888.27] + alt_bn128_G2::fixed_base_exp_window_table.push_back(4988); + // window 11 is unbeaten in [8888.27, 26271.13] + alt_bn128_G2::fixed_base_exp_window_table.push_back(8888); + // window 12 is unbeaten in [26271.13, 39768.20] + alt_bn128_G2::fixed_base_exp_window_table.push_back(26271); + // window 13 is unbeaten in [39768.20, 106275.75] + alt_bn128_G2::fixed_base_exp_window_table.push_back(39768); + // window 14 is unbeaten in [106275.75, 141703.40] + alt_bn128_G2::fixed_base_exp_window_table.push_back(106276); + // window 15 is unbeaten in [141703.40, 462422.97] + alt_bn128_G2::fixed_base_exp_window_table.push_back(141703); + // window 16 is unbeaten in [462422.97, 926871.84] + alt_bn128_G2::fixed_base_exp_window_table.push_back(462423); + // window 17 is unbeaten in [926871.84, 4873049.17] + alt_bn128_G2::fixed_base_exp_window_table.push_back(926872); + // window 18 is never the best + alt_bn128_G2::fixed_base_exp_window_table.push_back(0); + // window 19 is unbeaten in [4873049.17, 5706707.88] + alt_bn128_G2::fixed_base_exp_window_table.push_back(4873049); + // window 20 is unbeaten in [5706707.88, 31673814.95] + alt_bn128_G2::fixed_base_exp_window_table.push_back(5706708); + // window 21 is never the best + alt_bn128_G2::fixed_base_exp_window_table.push_back(0); + // window 22 is unbeaten in [31673814.95, inf] + alt_bn128_G2::fixed_base_exp_window_table.push_back(31673815); + + /* pairing parameters */ + + alt_bn128_ate_loop_count = bigint_q("29793968203157093288"); + alt_bn128_ate_is_loop_count_neg = false; + alt_bn128_final_exponent = bigint<12*alt_bn128_q_limbs>("552484233613224096312617126783173147097382103762957654188882734314196910839907541213974502761540629817009608548654680343627701153829446747810907373256841551006201639677726139946029199968412598804882391702273019083653272047566316584365559776493027495458238373902875937659943504873220554161550525926302303331747463515644711876653177129578303191095900909191624817826566688241804408081892785725967931714097716709526092261278071952560171111444072049229123565057483750161460024353346284167282452756217662335528813519139808291170539072125381230815729071544861602750936964829313608137325426383735122175229541155376346436093930287402089517426973178917569713384748081827255472576937471496195752727188261435633271238710131736096299798168852925540549342330775279877006784354801422249722573783561685179618816480037695005515426162362431072245638324744480"); + alt_bn128_final_exponent_z = bigint_q("4965661367192848881"); + alt_bn128_final_exponent_is_z_neg = false; + +} +} // libsnark diff --git a/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/alt_bn128/alt_bn128_init.hpp b/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/alt_bn128/alt_bn128_init.hpp new file mode 100644 index 0000000..c3bea76 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/alt_bn128/alt_bn128_init.hpp @@ -0,0 +1,57 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef ALT_BN128_INIT_HPP_ +#define ALT_BN128_INIT_HPP_ +#include "algebra/curves/public_params.hpp" +#include "algebra/fields/fp.hpp" +#include "algebra/fields/fp2.hpp" +#include "algebra/fields/fp6_3over2.hpp" +#include "algebra/fields/fp12_2over3over2.hpp" + +namespace libsnark { + +const mp_size_t alt_bn128_r_bitcount = 254; +const mp_size_t alt_bn128_q_bitcount = 254; + +const mp_size_t alt_bn128_r_limbs = (alt_bn128_r_bitcount+GMP_NUMB_BITS-1)/GMP_NUMB_BITS; +const mp_size_t alt_bn128_q_limbs = (alt_bn128_q_bitcount+GMP_NUMB_BITS-1)/GMP_NUMB_BITS; + +extern bigint alt_bn128_modulus_r; +extern bigint alt_bn128_modulus_q; + +typedef Fp_model alt_bn128_Fr; +typedef Fp_model alt_bn128_Fq; +typedef Fp2_model alt_bn128_Fq2; +typedef Fp6_3over2_model alt_bn128_Fq6; +typedef Fp12_2over3over2_model alt_bn128_Fq12; +typedef alt_bn128_Fq12 alt_bn128_GT; + +// parameters for Barreto--Naehrig curve E/Fq : y^2 = x^3 + b +extern alt_bn128_Fq alt_bn128_coeff_b; +// parameters for twisted Barreto--Naehrig curve E'/Fq2 : y^2 = x^3 + b/xi +extern alt_bn128_Fq2 alt_bn128_twist; +extern alt_bn128_Fq2 alt_bn128_twist_coeff_b; +extern alt_bn128_Fq alt_bn128_twist_mul_by_b_c0; +extern alt_bn128_Fq alt_bn128_twist_mul_by_b_c1; +extern alt_bn128_Fq2 alt_bn128_twist_mul_by_q_X; +extern alt_bn128_Fq2 alt_bn128_twist_mul_by_q_Y; + +// parameters for pairing +extern bigint alt_bn128_ate_loop_count; +extern bool alt_bn128_ate_is_loop_count_neg; +extern bigint<12*alt_bn128_q_limbs> alt_bn128_final_exponent; +extern bigint alt_bn128_final_exponent_z; +extern bool alt_bn128_final_exponent_is_z_neg; + +void init_alt_bn128_params(); + +class alt_bn128_G1; +class alt_bn128_G2; + +} // libsnark +#endif // ALT_BN128_INIT_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/alt_bn128/alt_bn128_pairing.cpp b/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/alt_bn128/alt_bn128_pairing.cpp new file mode 100644 index 0000000..3eb5aa1 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/alt_bn128/alt_bn128_pairing.cpp @@ -0,0 +1,546 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include "algebra/curves/alt_bn128/alt_bn128_pairing.hpp" +#include "algebra/curves/alt_bn128/alt_bn128_init.hpp" +#include "algebra/curves/alt_bn128/alt_bn128_g1.hpp" +#include "algebra/curves/alt_bn128/alt_bn128_g2.hpp" +#include +#include "common/profiling.hpp" + +namespace libsnark { + +bool alt_bn128_ate_G1_precomp::operator==(const alt_bn128_ate_G1_precomp &other) const +{ + return (this->PX == other.PX && + this->PY == other.PY); +} + +std::ostream& operator<<(std::ostream &out, const alt_bn128_ate_G1_precomp &prec_P) +{ + out << prec_P.PX << OUTPUT_SEPARATOR << prec_P.PY; + + return out; +} + +std::istream& operator>>(std::istream &in, alt_bn128_ate_G1_precomp &prec_P) +{ + in >> prec_P.PX; + consume_OUTPUT_SEPARATOR(in); + in >> prec_P.PY; + + return in; +} + +bool alt_bn128_ate_ell_coeffs::operator==(const alt_bn128_ate_ell_coeffs &other) const +{ + return (this->ell_0 == other.ell_0 && + this->ell_VW == other.ell_VW && + this->ell_VV == other.ell_VV); +} + +std::ostream& operator<<(std::ostream &out, const alt_bn128_ate_ell_coeffs &c) +{ + out << c.ell_0 << OUTPUT_SEPARATOR << c.ell_VW << OUTPUT_SEPARATOR << c.ell_VV; + return out; +} + +std::istream& operator>>(std::istream &in, alt_bn128_ate_ell_coeffs &c) +{ + in >> c.ell_0; + consume_OUTPUT_SEPARATOR(in); + in >> c.ell_VW; + consume_OUTPUT_SEPARATOR(in); + in >> c.ell_VV; + + return in; +} + +bool alt_bn128_ate_G2_precomp::operator==(const alt_bn128_ate_G2_precomp &other) const +{ + return (this->QX == other.QX && + this->QY == other.QY && + this->coeffs == other.coeffs); +} + +std::ostream& operator<<(std::ostream& out, const alt_bn128_ate_G2_precomp &prec_Q) +{ + out << prec_Q.QX << OUTPUT_SEPARATOR << prec_Q.QY << "\n"; + out << prec_Q.coeffs.size() << "\n"; + for (const alt_bn128_ate_ell_coeffs &c : prec_Q.coeffs) + { + out << c << OUTPUT_NEWLINE; + } + return out; +} + +std::istream& operator>>(std::istream& in, alt_bn128_ate_G2_precomp &prec_Q) +{ + in >> prec_Q.QX; + consume_OUTPUT_SEPARATOR(in); + in >> prec_Q.QY; + consume_newline(in); + + prec_Q.coeffs.clear(); + size_t s; + in >> s; + + consume_newline(in); + + prec_Q.coeffs.reserve(s); + + for (size_t i = 0; i < s; ++i) + { + alt_bn128_ate_ell_coeffs c; + in >> c; + consume_OUTPUT_NEWLINE(in); + prec_Q.coeffs.emplace_back(c); + } + + return in; +} + +/* final exponentiations */ + +alt_bn128_Fq12 alt_bn128_final_exponentiation_first_chunk(const alt_bn128_Fq12 &elt) +{ + enter_block("Call to alt_bn128_final_exponentiation_first_chunk"); + + /* + Computes result = elt^((q^6-1)*(q^2+1)). + Follows, e.g., Beuchat et al page 9, by computing result as follows: + elt^((q^6-1)*(q^2+1)) = (conj(elt) * elt^(-1))^(q^2+1) + More precisely: + A = conj(elt) + B = elt.inverse() + C = A * B + D = C.Frobenius_map(2) + result = D * C + */ + + const alt_bn128_Fq12 A = alt_bn128_Fq12(elt.c0,-elt.c1); + const alt_bn128_Fq12 B = elt.inverse(); + const alt_bn128_Fq12 C = A * B; + const alt_bn128_Fq12 D = C.Frobenius_map(2); + const alt_bn128_Fq12 result = D * C; + + leave_block("Call to alt_bn128_final_exponentiation_first_chunk"); + + return result; +} + +alt_bn128_Fq12 alt_bn128_exp_by_neg_z(const alt_bn128_Fq12 &elt) +{ + enter_block("Call to alt_bn128_exp_by_neg_z"); + + alt_bn128_Fq12 result = elt.cyclotomic_exp(alt_bn128_final_exponent_z); + if (!alt_bn128_final_exponent_is_z_neg) + { + result = result.unitary_inverse(); + } + + leave_block("Call to alt_bn128_exp_by_neg_z"); + + return result; +} + +alt_bn128_Fq12 alt_bn128_final_exponentiation_last_chunk(const alt_bn128_Fq12 &elt) +{ + enter_block("Call to alt_bn128_final_exponentiation_last_chunk"); + + /* + Follows Laura Fuentes-Castaneda et al. "Faster hashing to G2" + by computing: + + result = elt^(q^3 * (12*z^3 + 6z^2 + 4z - 1) + + q^2 * (12*z^3 + 6z^2 + 6z) + + q * (12*z^3 + 6z^2 + 4z) + + 1 * (12*z^3 + 12z^2 + 6z + 1)) + which equals + + result = elt^( 2z * ( 6z^2 + 3z + 1 ) * (q^4 - q^2 + 1)/r ). + + Using the following addition chain: + + A = exp_by_neg_z(elt) // = elt^(-z) + B = A^2 // = elt^(-2*z) + C = B^2 // = elt^(-4*z) + D = C * B // = elt^(-6*z) + E = exp_by_neg_z(D) // = elt^(6*z^2) + F = E^2 // = elt^(12*z^2) + G = epx_by_neg_z(F) // = elt^(-12*z^3) + H = conj(D) // = elt^(6*z) + I = conj(G) // = elt^(12*z^3) + J = I * E // = elt^(12*z^3 + 6*z^2) + K = J * H // = elt^(12*z^3 + 6*z^2 + 6*z) + L = K * B // = elt^(12*z^3 + 6*z^2 + 4*z) + M = K * E // = elt^(12*z^3 + 12*z^2 + 6*z) + N = M * elt // = elt^(12*z^3 + 12*z^2 + 6*z + 1) + O = L.Frobenius_map(1) // = elt^(q*(12*z^3 + 6*z^2 + 4*z)) + P = O * N // = elt^(q*(12*z^3 + 6*z^2 + 4*z) * (12*z^3 + 12*z^2 + 6*z + 1)) + Q = K.Frobenius_map(2) // = elt^(q^2 * (12*z^3 + 6*z^2 + 6*z)) + R = Q * P // = elt^(q^2 * (12*z^3 + 6*z^2 + 6*z) + q*(12*z^3 + 6*z^2 + 4*z) * (12*z^3 + 12*z^2 + 6*z + 1)) + S = conj(elt) // = elt^(-1) + T = S * L // = elt^(12*z^3 + 6*z^2 + 4*z - 1) + U = T.Frobenius_map(3) // = elt^(q^3(12*z^3 + 6*z^2 + 4*z - 1)) + V = U * R // = elt^(q^3(12*z^3 + 6*z^2 + 4*z - 1) + q^2 * (12*z^3 + 6*z^2 + 6*z) + q*(12*z^3 + 6*z^2 + 4*z) * (12*z^3 + 12*z^2 + 6*z + 1)) + result = V + + */ + + const alt_bn128_Fq12 A = alt_bn128_exp_by_neg_z(elt); + const alt_bn128_Fq12 B = A.cyclotomic_squared(); + const alt_bn128_Fq12 C = B.cyclotomic_squared(); + const alt_bn128_Fq12 D = C * B; + const alt_bn128_Fq12 E = alt_bn128_exp_by_neg_z(D); + const alt_bn128_Fq12 F = E.cyclotomic_squared(); + const alt_bn128_Fq12 G = alt_bn128_exp_by_neg_z(F); + const alt_bn128_Fq12 H = D.unitary_inverse(); + const alt_bn128_Fq12 I = G.unitary_inverse(); + const alt_bn128_Fq12 J = I * E; + const alt_bn128_Fq12 K = J * H; + const alt_bn128_Fq12 L = K * B; + const alt_bn128_Fq12 M = K * E; + const alt_bn128_Fq12 N = M * elt; + const alt_bn128_Fq12 O = L.Frobenius_map(1); + const alt_bn128_Fq12 P = O * N; + const alt_bn128_Fq12 Q = K.Frobenius_map(2); + const alt_bn128_Fq12 R = Q * P; + const alt_bn128_Fq12 S = elt.unitary_inverse(); + const alt_bn128_Fq12 T = S * L; + const alt_bn128_Fq12 U = T.Frobenius_map(3); + const alt_bn128_Fq12 V = U * R; + + const alt_bn128_Fq12 result = V; + + leave_block("Call to alt_bn128_final_exponentiation_last_chunk"); + + return result; +} + +alt_bn128_GT alt_bn128_final_exponentiation(const alt_bn128_Fq12 &elt) +{ + enter_block("Call to alt_bn128_final_exponentiation"); + /* OLD naive version: + alt_bn128_GT result = elt^alt_bn128_final_exponent; + */ + alt_bn128_Fq12 A = alt_bn128_final_exponentiation_first_chunk(elt); + alt_bn128_GT result = alt_bn128_final_exponentiation_last_chunk(A); + + leave_block("Call to alt_bn128_final_exponentiation"); + return result; +} + +/* ate pairing */ + +void doubling_step_for_flipped_miller_loop(const alt_bn128_Fq two_inv, + alt_bn128_G2 ¤t, + alt_bn128_ate_ell_coeffs &c) +{ + const alt_bn128_Fq2 X = current.X, Y = current.Y, Z = current.Z; + + const alt_bn128_Fq2 A = two_inv * (X * Y); // A = X1 * Y1 / 2 + const alt_bn128_Fq2 B = Y.squared(); // B = Y1^2 + const alt_bn128_Fq2 C = Z.squared(); // C = Z1^2 + const alt_bn128_Fq2 D = C+C+C; // D = 3 * C + const alt_bn128_Fq2 E = alt_bn128_twist_coeff_b * D; // E = twist_b * D + const alt_bn128_Fq2 F = E+E+E; // F = 3 * E + const alt_bn128_Fq2 G = two_inv * (B+F); // G = (B+F)/2 + const alt_bn128_Fq2 H = (Y+Z).squared() - (B+C); // H = (Y1+Z1)^2-(B+C) + const alt_bn128_Fq2 I = E-B; // I = E-B + const alt_bn128_Fq2 J = X.squared(); // J = X1^2 + const alt_bn128_Fq2 E_squared = E.squared(); // E_squared = E^2 + + current.X = A * (B-F); // X3 = A * (B-F) + current.Y = G.squared() - (E_squared+E_squared+E_squared); // Y3 = G^2 - 3*E^2 + current.Z = B * H; // Z3 = B * H + c.ell_0 = alt_bn128_twist * I; // ell_0 = xi * I + c.ell_VW = -H; // ell_VW = - H (later: * yP) + c.ell_VV = J+J+J; // ell_VV = 3*J (later: * xP) +} + +void mixed_addition_step_for_flipped_miller_loop(const alt_bn128_G2 base, + alt_bn128_G2 ¤t, + alt_bn128_ate_ell_coeffs &c) +{ + const alt_bn128_Fq2 X1 = current.X, Y1 = current.Y, Z1 = current.Z; + const alt_bn128_Fq2 &x2 = base.X, &y2 = base.Y; + + const alt_bn128_Fq2 D = X1 - x2 * Z1; // D = X1 - X2*Z1 + const alt_bn128_Fq2 E = Y1 - y2 * Z1; // E = Y1 - Y2*Z1 + const alt_bn128_Fq2 F = D.squared(); // F = D^2 + const alt_bn128_Fq2 G = E.squared(); // G = E^2 + const alt_bn128_Fq2 H = D*F; // H = D*F + const alt_bn128_Fq2 I = X1 * F; // I = X1 * F + const alt_bn128_Fq2 J = H + Z1*G - (I+I); // J = H + Z1*G - (I+I) + + current.X = D * J; // X3 = D*J + current.Y = E * (I-J)-(H * Y1); // Y3 = E*(I-J)-(H*Y1) + current.Z = Z1 * H; // Z3 = Z1*H + c.ell_0 = alt_bn128_twist * (E * x2 - D * y2); // ell_0 = xi * (E * X2 - D * Y2) + c.ell_VV = - E; // ell_VV = - E (later: * xP) + c.ell_VW = D; // ell_VW = D (later: * yP ) +} + +alt_bn128_ate_G1_precomp alt_bn128_ate_precompute_G1(const alt_bn128_G1& P) +{ + enter_block("Call to alt_bn128_ate_precompute_G1"); + + alt_bn128_G1 Pcopy = P; + Pcopy.to_affine_coordinates(); + + alt_bn128_ate_G1_precomp result; + result.PX = Pcopy.X; + result.PY = Pcopy.Y; + + leave_block("Call to alt_bn128_ate_precompute_G1"); + return result; +} + +alt_bn128_ate_G2_precomp alt_bn128_ate_precompute_G2(const alt_bn128_G2& Q) +{ + enter_block("Call to alt_bn128_ate_precompute_G2"); + + alt_bn128_G2 Qcopy(Q); + Qcopy.to_affine_coordinates(); + + alt_bn128_Fq two_inv = (alt_bn128_Fq("2").inverse()); // could add to global params if needed + + alt_bn128_ate_G2_precomp result; + result.QX = Qcopy.X; + result.QY = Qcopy.Y; + + alt_bn128_G2 R; + R.X = Qcopy.X; + R.Y = Qcopy.Y; + R.Z = alt_bn128_Fq2::one(); + + const bigint &loop_count = alt_bn128_ate_loop_count; + bool found_one = false; + alt_bn128_ate_ell_coeffs c; + + for (long i = loop_count.max_bits(); i >= 0; --i) + { + const bool bit = loop_count.test_bit(i); + if (!found_one) + { + /* this skips the MSB itself */ + found_one |= bit; + continue; + } + + doubling_step_for_flipped_miller_loop(two_inv, R, c); + result.coeffs.push_back(c); + + if (bit) + { + mixed_addition_step_for_flipped_miller_loop(Qcopy, R, c); + result.coeffs.push_back(c); + } + } + + alt_bn128_G2 Q1 = Qcopy.mul_by_q(); + assert(Q1.Z == alt_bn128_Fq2::one()); + alt_bn128_G2 Q2 = Q1.mul_by_q(); + assert(Q2.Z == alt_bn128_Fq2::one()); + + if (alt_bn128_ate_is_loop_count_neg) + { + R.Y = - R.Y; + } + Q2.Y = - Q2.Y; + + mixed_addition_step_for_flipped_miller_loop(Q1, R, c); + result.coeffs.push_back(c); + + mixed_addition_step_for_flipped_miller_loop(Q2, R, c); + result.coeffs.push_back(c); + + leave_block("Call to alt_bn128_ate_precompute_G2"); + return result; +} + +alt_bn128_Fq12 alt_bn128_ate_miller_loop(const alt_bn128_ate_G1_precomp &prec_P, + const alt_bn128_ate_G2_precomp &prec_Q) +{ + enter_block("Call to alt_bn128_ate_miller_loop"); + + alt_bn128_Fq12 f = alt_bn128_Fq12::one(); + + bool found_one = false; + size_t idx = 0; + + const bigint &loop_count = alt_bn128_ate_loop_count; + alt_bn128_ate_ell_coeffs c; + + for (long i = loop_count.max_bits(); i >= 0; --i) + { + const bool bit = loop_count.test_bit(i); + if (!found_one) + { + /* this skips the MSB itself */ + found_one |= bit; + continue; + } + + /* code below gets executed for all bits (EXCEPT the MSB itself) of + alt_bn128_param_p (skipping leading zeros) in MSB to LSB + order */ + + c = prec_Q.coeffs[idx++]; + f = f.squared(); + f = f.mul_by_024(c.ell_0, prec_P.PY * c.ell_VW, prec_P.PX * c.ell_VV); + + if (bit) + { + c = prec_Q.coeffs[idx++]; + f = f.mul_by_024(c.ell_0, prec_P.PY * c.ell_VW, prec_P.PX * c.ell_VV); + } + + } + + if (alt_bn128_ate_is_loop_count_neg) + { + f = f.inverse(); + } + + c = prec_Q.coeffs[idx++]; + f = f.mul_by_024(c.ell_0,prec_P.PY * c.ell_VW,prec_P.PX * c.ell_VV); + + c = prec_Q.coeffs[idx++]; + f = f.mul_by_024(c.ell_0,prec_P.PY * c.ell_VW,prec_P.PX * c.ell_VV); + + leave_block("Call to alt_bn128_ate_miller_loop"); + return f; +} + +alt_bn128_Fq12 alt_bn128_ate_double_miller_loop(const alt_bn128_ate_G1_precomp &prec_P1, + const alt_bn128_ate_G2_precomp &prec_Q1, + const alt_bn128_ate_G1_precomp &prec_P2, + const alt_bn128_ate_G2_precomp &prec_Q2) +{ + enter_block("Call to alt_bn128_ate_double_miller_loop"); + + alt_bn128_Fq12 f = alt_bn128_Fq12::one(); + + bool found_one = false; + size_t idx = 0; + + const bigint &loop_count = alt_bn128_ate_loop_count; + for (long i = loop_count.max_bits(); i >= 0; --i) + { + const bool bit = loop_count.test_bit(i); + if (!found_one) + { + /* this skips the MSB itself */ + found_one |= bit; + continue; + } + + /* code below gets executed for all bits (EXCEPT the MSB itself) of + alt_bn128_param_p (skipping leading zeros) in MSB to LSB + order */ + + alt_bn128_ate_ell_coeffs c1 = prec_Q1.coeffs[idx]; + alt_bn128_ate_ell_coeffs c2 = prec_Q2.coeffs[idx]; + ++idx; + + f = f.squared(); + + f = f.mul_by_024(c1.ell_0, prec_P1.PY * c1.ell_VW, prec_P1.PX * c1.ell_VV); + f = f.mul_by_024(c2.ell_0, prec_P2.PY * c2.ell_VW, prec_P2.PX * c2.ell_VV); + + if (bit) + { + alt_bn128_ate_ell_coeffs c1 = prec_Q1.coeffs[idx]; + alt_bn128_ate_ell_coeffs c2 = prec_Q2.coeffs[idx]; + ++idx; + + f = f.mul_by_024(c1.ell_0, prec_P1.PY * c1.ell_VW, prec_P1.PX * c1.ell_VV); + f = f.mul_by_024(c2.ell_0, prec_P2.PY * c2.ell_VW, prec_P2.PX * c2.ell_VV); + } + } + + if (alt_bn128_ate_is_loop_count_neg) + { + f = f.inverse(); + } + + alt_bn128_ate_ell_coeffs c1 = prec_Q1.coeffs[idx]; + alt_bn128_ate_ell_coeffs c2 = prec_Q2.coeffs[idx]; + ++idx; + f = f.mul_by_024(c1.ell_0, prec_P1.PY * c1.ell_VW, prec_P1.PX * c1.ell_VV); + f = f.mul_by_024(c2.ell_0, prec_P2.PY * c2.ell_VW, prec_P2.PX * c2.ell_VV); + + c1 = prec_Q1.coeffs[idx]; + c2 = prec_Q2.coeffs[idx]; + ++idx; + f = f.mul_by_024(c1.ell_0, prec_P1.PY * c1.ell_VW, prec_P1.PX * c1.ell_VV); + f = f.mul_by_024(c2.ell_0, prec_P2.PY * c2.ell_VW, prec_P2.PX * c2.ell_VV); + + leave_block("Call to alt_bn128_ate_double_miller_loop"); + + return f; +} + +alt_bn128_Fq12 alt_bn128_ate_pairing(const alt_bn128_G1& P, const alt_bn128_G2 &Q) +{ + enter_block("Call to alt_bn128_ate_pairing"); + alt_bn128_ate_G1_precomp prec_P = alt_bn128_ate_precompute_G1(P); + alt_bn128_ate_G2_precomp prec_Q = alt_bn128_ate_precompute_G2(Q); + alt_bn128_Fq12 result = alt_bn128_ate_miller_loop(prec_P, prec_Q); + leave_block("Call to alt_bn128_ate_pairing"); + return result; +} + +alt_bn128_GT alt_bn128_ate_reduced_pairing(const alt_bn128_G1 &P, const alt_bn128_G2 &Q) +{ + enter_block("Call to alt_bn128_ate_reduced_pairing"); + const alt_bn128_Fq12 f = alt_bn128_ate_pairing(P, Q); + const alt_bn128_GT result = alt_bn128_final_exponentiation(f); + leave_block("Call to alt_bn128_ate_reduced_pairing"); + return result; +} + +/* choice of pairing */ + +alt_bn128_G1_precomp alt_bn128_precompute_G1(const alt_bn128_G1& P) +{ + return alt_bn128_ate_precompute_G1(P); +} + +alt_bn128_G2_precomp alt_bn128_precompute_G2(const alt_bn128_G2& Q) +{ + return alt_bn128_ate_precompute_G2(Q); +} + +alt_bn128_Fq12 alt_bn128_miller_loop(const alt_bn128_G1_precomp &prec_P, + const alt_bn128_G2_precomp &prec_Q) +{ + return alt_bn128_ate_miller_loop(prec_P, prec_Q); +} + +alt_bn128_Fq12 alt_bn128_double_miller_loop(const alt_bn128_G1_precomp &prec_P1, + const alt_bn128_G2_precomp &prec_Q1, + const alt_bn128_G1_precomp &prec_P2, + const alt_bn128_G2_precomp &prec_Q2) +{ + return alt_bn128_ate_double_miller_loop(prec_P1, prec_Q1, prec_P2, prec_Q2); +} + +alt_bn128_Fq12 alt_bn128_pairing(const alt_bn128_G1& P, + const alt_bn128_G2 &Q) +{ + return alt_bn128_ate_pairing(P, Q); +} + +alt_bn128_GT alt_bn128_reduced_pairing(const alt_bn128_G1 &P, + const alt_bn128_G2 &Q) +{ + return alt_bn128_ate_reduced_pairing(P, Q); +} +} // libsnark diff --git a/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/alt_bn128/alt_bn128_pairing.hpp b/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/alt_bn128/alt_bn128_pairing.hpp new file mode 100644 index 0000000..15d3254 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/alt_bn128/alt_bn128_pairing.hpp @@ -0,0 +1,92 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef ALT_BN128_PAIRING_HPP_ +#define ALT_BN128_PAIRING_HPP_ +#include +#include "algebra/curves/alt_bn128/alt_bn128_init.hpp" + +namespace libsnark { + +/* final exponentiation */ + +alt_bn128_GT alt_bn128_final_exponentiation(const alt_bn128_Fq12 &elt); + +/* ate pairing */ + +struct alt_bn128_ate_G1_precomp { + alt_bn128_Fq PX; + alt_bn128_Fq PY; + + bool operator==(const alt_bn128_ate_G1_precomp &other) const; + friend std::ostream& operator<<(std::ostream &out, const alt_bn128_ate_G1_precomp &prec_P); + friend std::istream& operator>>(std::istream &in, alt_bn128_ate_G1_precomp &prec_P); +}; + +struct alt_bn128_ate_ell_coeffs { + alt_bn128_Fq2 ell_0; + alt_bn128_Fq2 ell_VW; + alt_bn128_Fq2 ell_VV; + + bool operator==(const alt_bn128_ate_ell_coeffs &other) const; + friend std::ostream& operator<<(std::ostream &out, const alt_bn128_ate_ell_coeffs &dc); + friend std::istream& operator>>(std::istream &in, alt_bn128_ate_ell_coeffs &dc); +}; + +struct alt_bn128_ate_G2_precomp { + alt_bn128_Fq2 QX; + alt_bn128_Fq2 QY; + std::vector coeffs; + + bool operator==(const alt_bn128_ate_G2_precomp &other) const; + friend std::ostream& operator<<(std::ostream &out, const alt_bn128_ate_G2_precomp &prec_Q); + friend std::istream& operator>>(std::istream &in, alt_bn128_ate_G2_precomp &prec_Q); +}; + +alt_bn128_ate_G1_precomp alt_bn128_ate_precompute_G1(const alt_bn128_G1& P); +alt_bn128_ate_G2_precomp alt_bn128_ate_precompute_G2(const alt_bn128_G2& Q); + +alt_bn128_Fq12 alt_bn128_ate_miller_loop(const alt_bn128_ate_G1_precomp &prec_P, + const alt_bn128_ate_G2_precomp &prec_Q); +alt_bn128_Fq12 alt_bn128_ate_double_miller_loop(const alt_bn128_ate_G1_precomp &prec_P1, + const alt_bn128_ate_G2_precomp &prec_Q1, + const alt_bn128_ate_G1_precomp &prec_P2, + const alt_bn128_ate_G2_precomp &prec_Q2); + +alt_bn128_Fq12 alt_bn128_ate_pairing(const alt_bn128_G1& P, + const alt_bn128_G2 &Q); +alt_bn128_GT alt_bn128_ate_reduced_pairing(const alt_bn128_G1 &P, + const alt_bn128_G2 &Q); + +/* choice of pairing */ + +typedef alt_bn128_ate_G1_precomp alt_bn128_G1_precomp; +typedef alt_bn128_ate_G2_precomp alt_bn128_G2_precomp; + +alt_bn128_G1_precomp alt_bn128_precompute_G1(const alt_bn128_G1& P); + +alt_bn128_G2_precomp alt_bn128_precompute_G2(const alt_bn128_G2& Q); + +alt_bn128_Fq12 alt_bn128_miller_loop(const alt_bn128_G1_precomp &prec_P, + const alt_bn128_G2_precomp &prec_Q); + +alt_bn128_Fq12 alt_bn128_double_miller_loop(const alt_bn128_G1_precomp &prec_P1, + const alt_bn128_G2_precomp &prec_Q1, + const alt_bn128_G1_precomp &prec_P2, + const alt_bn128_G2_precomp &prec_Q2); + +alt_bn128_Fq12 alt_bn128_pairing(const alt_bn128_G1& P, + const alt_bn128_G2 &Q); + +alt_bn128_GT alt_bn128_reduced_pairing(const alt_bn128_G1 &P, + const alt_bn128_G2 &Q); + +alt_bn128_GT alt_bn128_affine_reduced_pairing(const alt_bn128_G1 &P, + const alt_bn128_G2 &Q); + +} // libsnark +#endif // ALT_BN128_PAIRING_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/alt_bn128/alt_bn128_pp.cpp b/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/alt_bn128/alt_bn128_pp.cpp new file mode 100644 index 0000000..25ea924 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/alt_bn128/alt_bn128_pp.cpp @@ -0,0 +1,58 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include "algebra/curves/alt_bn128/alt_bn128_pp.hpp" + +namespace libsnark { + +void alt_bn128_pp::init_public_params() +{ + init_alt_bn128_params(); +} + +alt_bn128_GT alt_bn128_pp::final_exponentiation(const alt_bn128_Fq12 &elt) +{ + return alt_bn128_final_exponentiation(elt); +} + +alt_bn128_G1_precomp alt_bn128_pp::precompute_G1(const alt_bn128_G1 &P) +{ + return alt_bn128_precompute_G1(P); +} + +alt_bn128_G2_precomp alt_bn128_pp::precompute_G2(const alt_bn128_G2 &Q) +{ + return alt_bn128_precompute_G2(Q); +} + +alt_bn128_Fq12 alt_bn128_pp::miller_loop(const alt_bn128_G1_precomp &prec_P, + const alt_bn128_G2_precomp &prec_Q) +{ + return alt_bn128_miller_loop(prec_P, prec_Q); +} + +alt_bn128_Fq12 alt_bn128_pp::double_miller_loop(const alt_bn128_G1_precomp &prec_P1, + const alt_bn128_G2_precomp &prec_Q1, + const alt_bn128_G1_precomp &prec_P2, + const alt_bn128_G2_precomp &prec_Q2) +{ + return alt_bn128_double_miller_loop(prec_P1, prec_Q1, prec_P2, prec_Q2); +} + +alt_bn128_Fq12 alt_bn128_pp::pairing(const alt_bn128_G1 &P, + const alt_bn128_G2 &Q) +{ + return alt_bn128_pairing(P, Q); +} + +alt_bn128_Fq12 alt_bn128_pp::reduced_pairing(const alt_bn128_G1 &P, + const alt_bn128_G2 &Q) +{ + return alt_bn128_reduced_pairing(P, Q); +} + +} // libsnark diff --git a/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/alt_bn128/alt_bn128_pp.hpp b/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/alt_bn128/alt_bn128_pp.hpp new file mode 100644 index 0000000..ec8059d --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/alt_bn128/alt_bn128_pp.hpp @@ -0,0 +1,50 @@ +/** @file +***************************************************************************** +* @author This file is part of libsnark, developed by SCIPR Lab +* and contributors (see AUTHORS). +* @copyright MIT license (see LICENSE file) +*****************************************************************************/ + +#ifndef ALT_BN128_PP_HPP_ +#define ALT_BN128_PP_HPP_ +#include "algebra/curves/public_params.hpp" +#include "algebra/curves/alt_bn128/alt_bn128_init.hpp" +#include "algebra/curves/alt_bn128/alt_bn128_g1.hpp" +#include "algebra/curves/alt_bn128/alt_bn128_g2.hpp" +#include "algebra/curves/alt_bn128/alt_bn128_pairing.hpp" + +namespace libsnark { + +class alt_bn128_pp { +public: + typedef alt_bn128_Fr Fp_type; + typedef alt_bn128_G1 G1_type; + typedef alt_bn128_G2 G2_type; + typedef alt_bn128_G1_precomp G1_precomp_type; + typedef alt_bn128_G2_precomp G2_precomp_type; + typedef alt_bn128_Fq Fq_type; + typedef alt_bn128_Fq2 Fqe_type; + typedef alt_bn128_Fq12 Fqk_type; + typedef alt_bn128_GT GT_type; + + static const bool has_affine_pairing = false; + + static void init_public_params(); + static alt_bn128_GT final_exponentiation(const alt_bn128_Fq12 &elt); + static alt_bn128_G1_precomp precompute_G1(const alt_bn128_G1 &P); + static alt_bn128_G2_precomp precompute_G2(const alt_bn128_G2 &Q); + static alt_bn128_Fq12 miller_loop(const alt_bn128_G1_precomp &prec_P, + const alt_bn128_G2_precomp &prec_Q); + static alt_bn128_Fq12 double_miller_loop(const alt_bn128_G1_precomp &prec_P1, + const alt_bn128_G2_precomp &prec_Q1, + const alt_bn128_G1_precomp &prec_P2, + const alt_bn128_G2_precomp &prec_Q2); + static alt_bn128_Fq12 pairing(const alt_bn128_G1 &P, + const alt_bn128_G2 &Q); + static alt_bn128_Fq12 reduced_pairing(const alt_bn128_G1 &P, + const alt_bn128_G2 &Q); +}; + +} // libsnark + +#endif // ALT_BN128_PP_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/bn128/bn128_g1.cpp b/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/bn128/bn128_g1.cpp new file mode 100644 index 0000000..04a25c7 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/bn128/bn128_g1.cpp @@ -0,0 +1,520 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include "algebra/curves/bn128/bn128_g1.hpp" +#include "algebra/curves/bn128/bn_utils.hpp" + +namespace libsnark { + +#ifdef PROFILE_OP_COUNTS +long long bn128_G1::add_cnt = 0; +long long bn128_G1::dbl_cnt = 0; +#endif + +std::vector bn128_G1::wnaf_window_table; +std::vector bn128_G1::fixed_base_exp_window_table; +bn128_G1 bn128_G1::G1_zero; +bn128_G1 bn128_G1::G1_one; + +bn::Fp bn128_G1::sqrt(const bn::Fp &el) +{ + size_t v = bn128_Fq_s; + bn::Fp z = bn128_Fq_nqr_to_t; + bn::Fp w = mie::power(el, bn128_Fq_t_minus_1_over_2); + bn::Fp x = el * w; + bn::Fp b = x * w; + +#if DEBUG + // check if square with Euler's criterion + bn::Fp check = b; + for (size_t i = 0; i < v-1; ++i) + { + bn::Fp::square(check, check); + } + + assert(check == bn::Fp(1)); +#endif + + // compute square root with Tonelli--Shanks + // (does not terminate if not a square!) + + while (b != bn::Fp(1)) + { + size_t m = 0; + bn::Fp b2m = b; + while (b2m != bn::Fp(1)) + { + // invariant: b2m = b^(2^m) after entering this loop + bn::Fp::square(b2m, b2m); + m += 1; + } + + int j = v-m-1; + w = z; + while (j > 0) + { + bn::Fp::square(w, w); + --j; + } // w = z^2^(v-m-1) + + z = w * w; + b = b * z; + x = x * w; + v = m; + } + + return x; +} + +bn128_G1::bn128_G1() +{ + this->coord[0] = G1_zero.coord[0]; + this->coord[1] = G1_zero.coord[1]; + this->coord[2] = G1_zero.coord[2]; +} + +void bn128_G1::print() const +{ + if (this->is_zero()) + { + printf("O\n"); + } + else + { + bn128_G1 copy(*this); + copy.to_affine_coordinates(); + std::cout << "(" << copy.coord[0].toString(10) << " : " << copy.coord[1].toString(10) << " : " << copy.coord[2].toString(10) << ")\n"; + } +} + +void bn128_G1::print_coordinates() const +{ + if (this->is_zero()) + { + printf("O\n"); + } + else + { + std::cout << "(" << coord[0].toString(10) << " : " << coord[1].toString(10) << " : " << coord[2].toString(10) << ")\n"; + } +} + +void bn128_G1::to_affine_coordinates() +{ + if (this->is_zero()) + { + coord[0] = 0; + coord[1] = 1; + coord[2] = 0; + } + else + { + bn::Fp r; + r = coord[2]; + r.inverse(); + bn::Fp::square(coord[2], r); + coord[0] *= coord[2]; + r *= coord[2]; + coord[1] *= r; + coord[2] = 1; + } +} + +void bn128_G1::to_special() +{ + this->to_affine_coordinates(); +} + +bool bn128_G1::is_special() const +{ + return (this->is_zero() || this->coord[2] == 1); +} + +bool bn128_G1::is_zero() const +{ + return coord[2].isZero(); +} + +bool bn128_G1::operator==(const bn128_G1 &other) const +{ + if (this->is_zero()) + { + return other.is_zero(); + } + + if (other.is_zero()) + { + return false; + } + + /* now neither is O */ + + bn::Fp Z1sq, Z2sq, lhs, rhs; + bn::Fp::square(Z1sq, this->coord[2]); + bn::Fp::square(Z2sq, other.coord[2]); + bn::Fp::mul(lhs, Z2sq, this->coord[0]); + bn::Fp::mul(rhs, Z1sq, other.coord[0]); + + if (lhs != rhs) + { + return false; + } + + bn::Fp Z1cubed, Z2cubed; + bn::Fp::mul(Z1cubed, Z1sq, this->coord[2]); + bn::Fp::mul(Z2cubed, Z2sq, other.coord[2]); + bn::Fp::mul(lhs, Z2cubed, this->coord[1]); + bn::Fp::mul(rhs, Z1cubed, other.coord[1]); + + return (lhs == rhs); +} + +bool bn128_G1::operator!=(const bn128_G1& other) const +{ + return !(operator==(other)); +} + +bn128_G1 bn128_G1::operator+(const bn128_G1 &other) const +{ + // handle special cases having to do with O + if (this->is_zero()) + { + return other; + } + + if (other.is_zero()) + { + return *this; + } + + // no need to handle points of order 2,4 + // (they cannot exist in a prime-order subgroup) + + // handle double case, and then all the rest + if (this->operator==(other)) + { + return this->dbl(); + } + else + { + return this->add(other); + } +} + +bn128_G1 bn128_G1::operator-() const +{ + bn128_G1 result(*this); + bn::Fp::neg(result.coord[1], result.coord[1]); + return result; +} + +bn128_G1 bn128_G1::operator-(const bn128_G1 &other) const +{ + return (*this) + (-other); +} + +bn128_G1 bn128_G1::add(const bn128_G1 &other) const +{ +#ifdef PROFILE_OP_COUNTS + this->add_cnt++; +#endif + + bn128_G1 result; + bn::ecop::ECAdd(result.coord, this->coord, other.coord); + return result; +} + +bn128_G1 bn128_G1::mixed_add(const bn128_G1 &other) const +{ + if (this->is_zero()) + { + return other; + } + + if (other.is_zero()) + { + return *this; + } + + // no need to handle points of order 2,4 + // (they cannot exist in a prime-order subgroup) + +#ifdef DEBUG + assert(other.is_special()); +#endif + + // check for doubling case + + // using Jacobian coordinates so: + // (X1:Y1:Z1) = (X2:Y2:Z2) + // iff + // X1/Z1^2 == X2/Z2^2 and Y1/Z1^3 == Y2/Z2^3 + // iff + // X1 * Z2^2 == X2 * Z1^2 and Y1 * Z2^3 == Y2 * Z1^3 + + // we know that Z2 = 1 + + bn::Fp Z1Z1; + bn::Fp::square(Z1Z1, this->coord[2]); + const bn::Fp &U1 = this->coord[0]; + bn::Fp U2; + bn::Fp::mul(U2, other.coord[0], Z1Z1); + bn::Fp Z1_cubed; + bn::Fp::mul(Z1_cubed, this->coord[2], Z1Z1); + + const bn::Fp &S1 = this->coord[1]; + bn::Fp S2; + bn::Fp::mul(S2, other.coord[1], Z1_cubed); // S2 = Y2*Z1*Z1Z1 + + if (U1 == U2 && S1 == S2) + { + // dbl case; nothing of above can be reused + return this->dbl(); + } + +#ifdef PROFILE_OP_COUNTS + this->add_cnt++; +#endif + + bn128_G1 result; + bn::Fp H, HH, I, J, r, V, tmp; + // H = U2-X1 + bn::Fp::sub(H, U2, this->coord[0]); + // HH = H^2 + bn::Fp::square(HH, H); + // I = 4*HH + bn::Fp::add(tmp, HH, HH); + bn::Fp::add(I, tmp, tmp); + // J = H*I + bn::Fp::mul(J, H, I); + // r = 2*(S2-Y1) + bn::Fp::sub(tmp, S2, this->coord[1]); + bn::Fp::add(r, tmp, tmp); + // V = X1*I + bn::Fp::mul(V, this->coord[0], I); + // X3 = r^2-J-2*V + bn::Fp::square(result.coord[0], r); + bn::Fp::sub(result.coord[0], result.coord[0], J); + bn::Fp::sub(result.coord[0], result.coord[0], V); + bn::Fp::sub(result.coord[0], result.coord[0], V); + // Y3 = r*(V-X3)-2*Y1*J + bn::Fp::sub(tmp, V, result.coord[0]); + bn::Fp::mul(result.coord[1], r, tmp); + bn::Fp::mul(tmp, this->coord[1], J); + bn::Fp::sub(result.coord[1], result.coord[1], tmp); + bn::Fp::sub(result.coord[1], result.coord[1], tmp); + // Z3 = (Z1+H)^2-Z1Z1-HH + bn::Fp::add(tmp, this->coord[2], H); + bn::Fp::square(result.coord[2], tmp); + bn::Fp::sub(result.coord[2], result.coord[2], Z1Z1); + bn::Fp::sub(result.coord[2], result.coord[2], HH); + return result; +} + +bn128_G1 bn128_G1::dbl() const +{ +#ifdef PROFILE_OP_COUNTS + this->dbl_cnt++; +#endif + + bn128_G1 result; + bn::ecop::ECDouble(result.coord, this->coord); + return result; +} + +bn128_G1 bn128_G1::zero() +{ + return G1_zero; +} + +bn128_G1 bn128_G1::one() +{ + return G1_one; +} + +bn128_G1 bn128_G1::random_element() +{ + return bn128_Fr::random_element().as_bigint() * G1_one; +} + +std::ostream& operator<<(std::ostream &out, const bn128_G1 &g) +{ + bn128_G1 gcopy(g); + gcopy.to_affine_coordinates(); + + out << (gcopy.is_zero() ? '1' : '0') << OUTPUT_SEPARATOR; + +#ifdef NO_PT_COMPRESSION + /* no point compression case */ +#ifndef BINARY_OUTPUT + out << gcopy.coord[0] << OUTPUT_SEPARATOR << gcopy.coord[1]; +#else + out.write((char*) &gcopy.coord[0], sizeof(gcopy.coord[0])); + out.write((char*) &gcopy.coord[1], sizeof(gcopy.coord[1])); +#endif + +#else + /* point compression case */ +#ifndef BINARY_OUTPUT + out << gcopy.coord[0]; +#else + out.write((char*) &gcopy.coord[0], sizeof(gcopy.coord[0])); +#endif + out << OUTPUT_SEPARATOR << (((unsigned char*)&gcopy.coord[1])[0] & 1 ? '1' : '0'); +#endif + + return out; +} + +bool bn128_G1::is_well_formed() const +{ + if (this->is_zero()) + { + return true; + } + else + { + /* + y^2 = x^3 + b + + We are using Jacobian coordinates, so equation we need to check is actually + + (y/z^3)^2 = (x/z^2)^3 + b + y^2 / z^6 = x^3 / z^6 + b + y^2 = x^3 + b z^6 + */ + bn::Fp X2, Y2, Z2; + bn::Fp::square(X2, this->coord[0]); + bn::Fp::square(Y2, this->coord[1]); + bn::Fp::square(Z2, this->coord[2]); + + bn::Fp X3, Z3, Z6; + bn::Fp::mul(X3, X2, this->coord[0]); + bn::Fp::mul(Z3, Z2, this->coord[2]); + bn::Fp::square(Z6, Z3); + + return (Y2 == X3 + bn128_coeff_b * Z6); + } +} + +std::istream& operator>>(std::istream &in, bn128_G1 &g) +{ + char is_zero; + in.read((char*)&is_zero, 1); // this reads is_zero; + is_zero -= '0'; + consume_OUTPUT_SEPARATOR(in); + +#ifdef NO_PT_COMPRESSION + /* no point compression case */ +#ifndef BINARY_OUTPUT + in >> g.coord[0]; + consume_OUTPUT_SEPARATOR(in); + in >> g.coord[1]; +#else + in.read((char*) &g.coord[0], sizeof(g.coord[0])); + in.read((char*) &g.coord[1], sizeof(g.coord[1])); +#endif + +#else + /* point compression case */ + bn::Fp tX; +#ifndef BINARY_OUTPUT + in >> tX; +#else + in.read((char*)&tX, sizeof(tX)); +#endif + consume_OUTPUT_SEPARATOR(in); + unsigned char Y_lsb; + in.read((char*)&Y_lsb, 1); + Y_lsb -= '0'; + + // y = +/- sqrt(x^3 + b) + if (!is_zero) + { + g.coord[0] = tX; + bn::Fp tX2, tY2; + bn::Fp::square(tX2, tX); + bn::Fp::mul(tY2, tX2, tX); + bn::Fp::add(tY2, tY2, bn128_coeff_b); + + g.coord[1] = bn128_G1::sqrt(tY2); + if ((((unsigned char*)&g.coord[1])[0] & 1) != Y_lsb) + { + bn::Fp::neg(g.coord[1], g.coord[1]); + } + } +#endif + + /* finalize */ + if (!is_zero) + { + g.coord[2] = bn::Fp(1); + } + else + { + g = bn128_G1::zero(); + } + + return in; +} + +std::ostream& operator<<(std::ostream& out, const std::vector &v) +{ + out << v.size() << "\n"; + for (const bn128_G1& t : v) + { + out << t << OUTPUT_NEWLINE; + } + return out; +} + +std::istream& operator>>(std::istream& in, std::vector &v) +{ + v.clear(); + + size_t s; + in >> s; + consume_newline(in); + v.reserve(s); + + for (size_t i = 0; i < s; ++i) + { + bn128_G1 g; + in >> g; + consume_OUTPUT_NEWLINE(in); + v.emplace_back(g); + } + return in; +} + +template<> +void batch_to_special_all_non_zeros(std::vector &vec) +{ + std::vector Z_vec; + Z_vec.reserve(vec.size()); + + for (auto &el: vec) + { + Z_vec.emplace_back(el.coord[2]); + } + bn_batch_invert(Z_vec); + + const bn::Fp one = 1; + + for (size_t i = 0; i < vec.size(); ++i) + { + bn::Fp Z2, Z3; + bn::Fp::square(Z2, Z_vec[i]); + bn::Fp::mul(Z3, Z2, Z_vec[i]); + + bn::Fp::mul(vec[i].coord[0], vec[i].coord[0], Z2); + bn::Fp::mul(vec[i].coord[1], vec[i].coord[1], Z3); + vec[i].coord[2] = one; + } +} + +} // libsnark diff --git a/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/bn128/bn128_g1.hpp b/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/bn128/bn128_g1.hpp new file mode 100644 index 0000000..77d78ef --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/bn128/bn128_g1.hpp @@ -0,0 +1,94 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef BN128_G1_HPP_ +#define BN128_G1_HPP_ +#include +#include "algebra/curves/bn128/bn128_init.hpp" +#include "algebra/curves/curve_utils.hpp" +#include "bn.h" + +namespace libsnark { + +class bn128_G1; +std::ostream& operator<<(std::ostream &, const bn128_G1&); +std::istream& operator>>(std::istream &, bn128_G1&); + +class bn128_G1 { +private: + static bn::Fp sqrt(const bn::Fp &el); +public: +#ifdef PROFILE_OP_COUNTS + static long long add_cnt; + static long long dbl_cnt; +#endif + static std::vector wnaf_window_table; + static std::vector fixed_base_exp_window_table; + static bn128_G1 G1_zero; + static bn128_G1 G1_one; + + bn::Fp coord[3]; + bn128_G1(); + typedef bn128_Fq base_field; + typedef bn128_Fr scalar_field; + + void print() const; + void print_coordinates() const; + + void to_affine_coordinates(); + void to_special(); + bool is_special() const; + + bool is_zero() const; + + bool operator==(const bn128_G1 &other) const; + bool operator!=(const bn128_G1 &other) const; + + bn128_G1 operator+(const bn128_G1 &other) const; + bn128_G1 operator-() const; + bn128_G1 operator-(const bn128_G1 &other) const; + + bn128_G1 add(const bn128_G1 &other) const; + bn128_G1 mixed_add(const bn128_G1 &other) const; + bn128_G1 dbl() const; + + bool is_well_formed() const; + + static bn128_G1 zero(); + static bn128_G1 one(); + static bn128_G1 random_element(); + + static size_t size_in_bits() { return bn128_Fq::size_in_bits() + 1; } + static bigint base_field_char() { return base_field::field_char(); } + static bigint order() { return scalar_field::field_char(); } + + friend std::ostream& operator<<(std::ostream &out, const bn128_G1 &g); + friend std::istream& operator>>(std::istream &in, bn128_G1 &g); +}; + +template +bn128_G1 operator*(const bigint &lhs, const bn128_G1 &rhs) +{ + return scalar_mul(rhs, lhs); +} + +template& modulus_p> +bn128_G1 operator*(const Fp_model &lhs, const bn128_G1 &rhs) +{ + return scalar_mul(rhs, lhs.as_bigint()); +} + +std::ostream& operator<<(std::ostream& out, const std::vector &v); +std::istream& operator>>(std::istream& in, std::vector &v); + +template +void batch_to_special_all_non_zeros(std::vector &vec); +template<> +void batch_to_special_all_non_zeros(std::vector &vec); + +} // libsnark +#endif // BN128_G1_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/bn128/bn128_g2.cpp b/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/bn128/bn128_g2.cpp new file mode 100644 index 0000000..061fe89 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/bn128/bn128_g2.cpp @@ -0,0 +1,503 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include "algebra/curves/bn128/bn128_g2.hpp" +#include "algebra/curves/bn128/bn_utils.hpp" + +namespace libsnark { + +#ifdef PROFILE_OP_COUNTS +long long bn128_G2::add_cnt = 0; +long long bn128_G2::dbl_cnt = 0; +#endif + +std::vector bn128_G2::wnaf_window_table; +std::vector bn128_G2::fixed_base_exp_window_table; +bn128_G2 bn128_G2::G2_zero; +bn128_G2 bn128_G2::G2_one; + +bn::Fp2 bn128_G2::sqrt(const bn::Fp2 &el) +{ + size_t v = bn128_Fq2_s; + bn::Fp2 z = bn128_Fq2_nqr_to_t; + bn::Fp2 w = mie::power(el, bn128_Fq2_t_minus_1_over_2); + bn::Fp2 x = el * w; + bn::Fp2 b = x * w; + +#if DEBUG + // check if square with Euler's criterion + bn::Fp2 check = b; + for (size_t i = 0; i < v-1; ++i) + { + bn::Fp2::square(check, check); + } + + assert(check == bn::Fp2(bn::Fp(1), bn::Fp(0))); +#endif + + // compute square root with Tonelli--Shanks + // (does not terminate if not a square!) + + while (b != bn::Fp2(1)) + { + size_t m = 0; + bn::Fp2 b2m = b; + while (b2m != bn::Fp2(bn::Fp(1), bn::Fp(0))) + { + // invariant: b2m = b^(2^m) after entering this loop + bn::Fp2::square(b2m, b2m); + m += 1; + } + + int j = v-m-1; + w = z; + while (j > 0) + { + bn::Fp2::square(w, w); + --j; + } // w = z^2^(v-m-1) + + z = w * w; + b = b * z; + x = x * w; + v = m; + } + + return x; +} + +bn128_G2::bn128_G2() +{ + this->coord[0] = G2_zero.coord[0]; + this->coord[1] = G2_zero.coord[1]; + this->coord[2] = G2_zero.coord[2]; +} + +void bn128_G2::print() const +{ + if (this->is_zero()) + { + printf("O\n"); + } + else + { + bn128_G2 copy(*this); + copy.to_affine_coordinates(); + std::cout << "(" << copy.coord[0].toString(10) << " : " << copy.coord[1].toString(10) << " : " << copy.coord[2].toString(10) << ")\n"; + } +} + +void bn128_G2::print_coordinates() const +{ + if (this->is_zero()) + { + printf("O\n"); + } + else + { + std::cout << "(" << coord[0].toString(10) << " : " << coord[1].toString(10) << " : " << coord[2].toString(10) << ")\n"; + } +} + +void bn128_G2::to_affine_coordinates() +{ + if (this->is_zero()) + { + coord[0] = 0; + coord[1] = 1; + coord[2] = 0; + } + else + { + bn::Fp2 r; + r = coord[2]; + r.inverse(); + bn::Fp2::square(coord[2], r); + coord[0] *= coord[2]; + r *= coord[2]; + coord[1] *= r; + coord[2] = 1; + } +} + +void bn128_G2::to_special() +{ + this->to_affine_coordinates(); +} + +bool bn128_G2::is_special() const +{ + return (this->is_zero() || this->coord[2] == 1); +} + +bool bn128_G2::is_zero() const +{ + return coord[2].isZero(); +} + +bool bn128_G2::operator==(const bn128_G2 &other) const +{ + if (this->is_zero()) + { + return other.is_zero(); + } + + if (other.is_zero()) + { + return false; + } + + /* now neither is O */ + + bn::Fp2 Z1sq, Z2sq, lhs, rhs; + bn::Fp2::square(Z1sq, this->coord[2]); + bn::Fp2::square(Z2sq, other.coord[2]); + bn::Fp2::mul(lhs, Z2sq, this->coord[0]); + bn::Fp2::mul(rhs, Z1sq, other.coord[0]); + + if (lhs != rhs) + { + return false; + } + + bn::Fp2 Z1cubed, Z2cubed; + bn::Fp2::mul(Z1cubed, Z1sq, this->coord[2]); + bn::Fp2::mul(Z2cubed, Z2sq, other.coord[2]); + bn::Fp2::mul(lhs, Z2cubed, this->coord[1]); + bn::Fp2::mul(rhs, Z1cubed, other.coord[1]); + + return (lhs == rhs); +} + +bool bn128_G2::operator!=(const bn128_G2& other) const +{ + return !(operator==(other)); +} + +bn128_G2 bn128_G2::operator+(const bn128_G2 &other) const +{ + // handle special cases having to do with O + if (this->is_zero()) + { + return other; + } + + if (other.is_zero()) + { + return *this; + } + + // no need to handle points of order 2,4 + // (they cannot exist in a prime-order subgroup) + + // handle double case, and then all the rest + if (this->operator==(other)) + { + return this->dbl(); + } + else + { + return this->add(other); + } +} + +bn128_G2 bn128_G2::operator-() const +{ + bn128_G2 result(*this); + bn::Fp2::neg(result.coord[1], result.coord[1]); + return result; +} + +bn128_G2 bn128_G2::operator-(const bn128_G2 &other) const +{ + return (*this) + (-other); +} + +bn128_G2 bn128_G2::add(const bn128_G2 &other) const +{ +#ifdef PROFILE_OP_COUNTS + this->add_cnt++; +#endif + + bn128_G2 result; + bn::ecop::ECAdd(result.coord, this->coord, other.coord); + return result; +} + +bn128_G2 bn128_G2::mixed_add(const bn128_G2 &other) const +{ + if (this->is_zero()) + { + return other; + } + + if (other.is_zero()) + { + return *this; + } + + // no need to handle points of order 2,4 + // (they cannot exist in a prime-order subgroup) + +#ifdef DEBUG + assert(other.is_special()); +#endif + + // check for doubling case + + // using Jacobian coordinates so: + // (X1:Y1:Z1) = (X2:Y2:Z2) + // iff + // X1/Z1^2 == X2/Z2^2 and Y1/Z1^3 == Y2/Z2^3 + // iff + // X1 * Z2^2 == X2 * Z1^2 and Y1 * Z2^3 == Y2 * Z1^3 + + // we know that Z2 = 1 + + bn::Fp2 Z1Z1; + bn::Fp2::square(Z1Z1, this->coord[2]); + const bn::Fp2 &U1 = this->coord[0]; + bn::Fp2 U2; + bn::Fp2::mul(U2, other.coord[0], Z1Z1); + bn::Fp2 Z1_cubed; + bn::Fp2::mul(Z1_cubed, this->coord[2], Z1Z1); + + const bn::Fp2 &S1 = this->coord[1]; + bn::Fp2 S2; + bn::Fp2::mul(S2, other.coord[1], Z1_cubed); // S2 = Y2*Z1*Z1Z1 + + if (U1 == U2 && S1 == S2) + { + // dbl case; nothing of above can be reused + return this->dbl(); + } + +#ifdef PROFILE_OP_COUNTS + this->add_cnt++; +#endif + + bn128_G2 result; + bn::Fp2 H, HH, I, J, r, V, tmp; + // H = U2-X1 + bn::Fp2::sub(H, U2, this->coord[0]); + // HH = H^2 + bn::Fp2::square(HH, H); + // I = 4*HH + bn::Fp2::add(tmp, HH, HH); + bn::Fp2::add(I, tmp, tmp); + // J = H*I + bn::Fp2::mul(J, H, I); + // r = 2*(S2-Y1) + bn::Fp2::sub(tmp, S2, this->coord[1]); + bn::Fp2::add(r, tmp, tmp); + // V = X1*I + bn::Fp2::mul(V, this->coord[0], I); + // X3 = r^2-J-2*V + bn::Fp2::square(result.coord[0], r); + bn::Fp2::sub(result.coord[0], result.coord[0], J); + bn::Fp2::sub(result.coord[0], result.coord[0], V); + bn::Fp2::sub(result.coord[0], result.coord[0], V); + // Y3 = r*(V-X3)-2*Y1*J + bn::Fp2::sub(tmp, V, result.coord[0]); + bn::Fp2::mul(result.coord[1], r, tmp); + bn::Fp2::mul(tmp, this->coord[1], J); + bn::Fp2::sub(result.coord[1], result.coord[1], tmp); + bn::Fp2::sub(result.coord[1], result.coord[1], tmp); + // Z3 = (Z1+H)^2-Z1Z1-HH + bn::Fp2::add(tmp, this->coord[2], H); + bn::Fp2::square(result.coord[2], tmp); + bn::Fp2::sub(result.coord[2], result.coord[2], Z1Z1); + bn::Fp2::sub(result.coord[2], result.coord[2], HH); + return result; +} + +bn128_G2 bn128_G2::dbl() const +{ +#ifdef PROFILE_OP_COUNTS + this->dbl_cnt++; +#endif + bn128_G2 result; + bn::ecop::ECDouble(result.coord, this->coord); + return result; +} + +bool bn128_G2::is_well_formed() const +{ + if (this->is_zero()) + { + return true; + } + else + { + /* + y^2 = x^3 + b + + We are using Jacobian coordinates, so equation we need to check is actually + + (y/z^3)^2 = (x/z^2)^3 + b + y^2 / z^6 = x^3 / z^6 + b + y^2 = x^3 + b z^6 + */ + bn::Fp2 X2, Y2, Z2; + bn::Fp2::square(X2, this->coord[0]); + bn::Fp2::square(Y2, this->coord[1]); + bn::Fp2::square(Z2, this->coord[2]); + + bn::Fp2 X3, Z3, Z6; + bn::Fp2::mul(X3, X2, this->coord[0]); + bn::Fp2::mul(Z3, Z2, this->coord[2]); + bn::Fp2::square(Z6, Z3); + + return (Y2 == X3 + bn128_twist_coeff_b * Z6); + } +} + +bn128_G2 bn128_G2::zero() +{ + return G2_zero; +} + +bn128_G2 bn128_G2::one() +{ + return G2_one; +} + +bn128_G2 bn128_G2::random_element() +{ + return bn128_Fr::random_element().as_bigint() * G2_one; +} + +std::ostream& operator<<(std::ostream &out, const bn128_G2 &g) +{ + bn128_G2 gcopy(g); + gcopy.to_affine_coordinates(); + + out << (gcopy.is_zero() ? '1' : '0') << OUTPUT_SEPARATOR; + +#ifdef NO_PT_COMPRESSION + /* no point compression case */ +#ifndef BINARY_OUTPUT + out << gcopy.coord[0].a_ << OUTPUT_SEPARATOR << gcopy.coord[0].b_ << OUTPUT_SEPARATOR; + out << gcopy.coord[1].a_ << OUTPUT_SEPARATOR << gcopy.coord[1].b_; +#else + out.write((char*) &gcopy.coord[0].a_, sizeof(gcopy.coord[0].a_)); + out.write((char*) &gcopy.coord[0].b_, sizeof(gcopy.coord[0].b_)); + out.write((char*) &gcopy.coord[1].a_, sizeof(gcopy.coord[1].a_)); + out.write((char*) &gcopy.coord[1].b_, sizeof(gcopy.coord[1].b_)); +#endif + +#else + /* point compression case */ +#ifndef BINARY_OUTPUT + out << gcopy.coord[0].a_ << OUTPUT_SEPARATOR << gcopy.coord[0].b_; +#else + out.write((char*) &gcopy.coord[0].a_, sizeof(gcopy.coord[0].a_)); + out.write((char*) &gcopy.coord[0].b_, sizeof(gcopy.coord[0].b_)); +#endif + out << OUTPUT_SEPARATOR << (((unsigned char*)&gcopy.coord[1].a_)[0] & 1 ? '1' : '0'); +#endif + + return out; +} + +std::istream& operator>>(std::istream &in, bn128_G2 &g) +{ + char is_zero; + in.read((char*)&is_zero, 1); // this reads is_zero; + is_zero -= '0'; + consume_OUTPUT_SEPARATOR(in); + +#ifdef NO_PT_COMPRESSION + /* no point compression case */ +#ifndef BINARY_OUTPUT + in >> g.coord[0].a_; + consume_OUTPUT_SEPARATOR(in); + in >> g.coord[0].b_; + consume_OUTPUT_SEPARATOR(in); + in >> g.coord[1].a_; + consume_OUTPUT_SEPARATOR(in); + in >> g.coord[1].b_; +#else + in.read((char*) &g.coord[0].a_, sizeof(g.coord[0].a_)); + in.read((char*) &g.coord[0].b_, sizeof(g.coord[0].b_)); + in.read((char*) &g.coord[1].a_, sizeof(g.coord[1].a_)); + in.read((char*) &g.coord[1].b_, sizeof(g.coord[1].b_)); +#endif + +#else + /* point compression case */ + bn::Fp2 tX; +#ifndef BINARY_OUTPUT + in >> tX.a_; + consume_OUTPUT_SEPARATOR(in); + in >> tX.b_; +#else + in.read((char*)&tX.a_, sizeof(tX.a_)); + in.read((char*)&tX.b_, sizeof(tX.b_)); +#endif + consume_OUTPUT_SEPARATOR(in); + unsigned char Y_lsb; + in.read((char*)&Y_lsb, 1); + Y_lsb -= '0'; + + // y = +/- sqrt(x^3 + b) + if (!is_zero) + { + g.coord[0] = tX; + bn::Fp2 tX2, tY2; + bn::Fp2::square(tX2, tX); + bn::Fp2::mul(tY2, tX2, tX); + bn::Fp2::add(tY2, tY2, bn128_twist_coeff_b); + + g.coord[1] = bn128_G2::sqrt(tY2); + if ((((unsigned char*)&g.coord[1].a_)[0] & 1) != Y_lsb) + { + bn::Fp2::neg(g.coord[1], g.coord[1]); + } + } +#endif + + /* finalize */ + if (!is_zero) + { + g.coord[2] = bn::Fp2(bn::Fp(1), bn::Fp(0)); + } + else + { + g = bn128_G2::zero(); + } + + return in; +} + +template<> +void batch_to_special_all_non_zeros(std::vector &vec) +{ + std::vector Z_vec; + Z_vec.reserve(vec.size()); + + for (auto &el: vec) + { + Z_vec.emplace_back(el.coord[2]); + } + bn_batch_invert(Z_vec); + + const bn::Fp2 one = 1; + + for (size_t i = 0; i < vec.size(); ++i) + { + bn::Fp2 Z2, Z3; + bn::Fp2::square(Z2, Z_vec[i]); + bn::Fp2::mul(Z3, Z2, Z_vec[i]); + + bn::Fp2::mul(vec[i].coord[0], vec[i].coord[0], Z2); + bn::Fp2::mul(vec[i].coord[1], vec[i].coord[1], Z3); + vec[i].coord[2] = one; + } +} + +} // libsnark diff --git a/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/bn128/bn128_g2.hpp b/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/bn128/bn128_g2.hpp new file mode 100644 index 0000000..dba9c6b --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/bn128/bn128_g2.hpp @@ -0,0 +1,92 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef BN128_G2_HPP_ +#define BN128_G2_HPP_ +#include +#include +#include "algebra/curves/bn128/bn128_init.hpp" +#include "algebra/curves/curve_utils.hpp" +#include "bn.h" + +namespace libsnark { + +class bn128_G2; +std::ostream& operator<<(std::ostream &, const bn128_G2&); +std::istream& operator>>(std::istream &, bn128_G2&); + +class bn128_G2 { +private: + static bn::Fp2 sqrt(const bn::Fp2 &el); +public: +#ifdef PROFILE_OP_COUNTS + static long long add_cnt; + static long long dbl_cnt; +#endif + static std::vector wnaf_window_table; + static std::vector fixed_base_exp_window_table; + static bn128_G2 G2_zero; + static bn128_G2 G2_one; + + bn::Fp2 coord[3]; + bn128_G2(); + typedef bn128_Fq base_field; + typedef bn128_Fr scalar_field; + + void print() const; + void print_coordinates() const; + + void to_affine_coordinates(); + void to_special(); + bool is_special() const; + + bool is_zero() const; + + bool operator==(const bn128_G2 &other) const; + bool operator!=(const bn128_G2 &other) const; + + bn128_G2 operator+(const bn128_G2 &other) const; + bn128_G2 operator-() const; + bn128_G2 operator-(const bn128_G2 &other) const; + + bn128_G2 add(const bn128_G2 &other) const; + bn128_G2 mixed_add(const bn128_G2 &other) const; + bn128_G2 dbl() const; + + bool is_well_formed() const; + + static bn128_G2 zero(); + static bn128_G2 one(); + static bn128_G2 random_element(); + + static size_t size_in_bits() { return 2*base_field::size_in_bits() + 1; } + static bigint base_field_char() { return base_field::field_char(); } + static bigint order() { return scalar_field::field_char(); } + + friend std::ostream& operator<<(std::ostream &out, const bn128_G2 &g); + friend std::istream& operator>>(std::istream &in, bn128_G2 &g); +}; + +template +bn128_G2 operator*(const bigint &lhs, const bn128_G2 &rhs) +{ + return scalar_mul(rhs, lhs); +} + +template& modulus_p> +bn128_G2 operator*(const Fp_model &lhs, const bn128_G2 &rhs) +{ + return scalar_mul(rhs, lhs.as_bigint()); +} + +template +void batch_to_special_all_non_zeros(std::vector &vec); +template<> +void batch_to_special_all_non_zeros(std::vector &vec); + +} // libsnark +#endif // BN128_G2_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/bn128/bn128_gt.cpp b/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/bn128/bn128_gt.cpp new file mode 100644 index 0000000..8c0d785 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/bn128/bn128_gt.cpp @@ -0,0 +1,70 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include "algebra/curves/bn128/bn128_gt.hpp" + +namespace libsnark { + +bn128_GT bn128_GT::GT_one; +bn128_GT::bn128_GT() +{ + this->elem.clear(); +} + +bool bn128_GT::operator==(const bn128_GT &other) const +{ + return (this->elem == other.elem); +} + +bool bn128_GT::operator!=(const bn128_GT& other) const +{ + return !(operator==(other)); +} + +bn128_GT bn128_GT::operator*(const bn128_GT &other) const +{ + bn128_GT result; + bn::Fp12::mul(result.elem, this->elem, other.elem); + return result; +} + +bn128_GT bn128_GT::unitary_inverse() const +{ + bn128_GT result(*this); + bn::Fp6::neg(result.elem.b_, result.elem.b_); + return result; +} + +bn128_GT bn128_GT::one() +{ + return GT_one; +} + +std::ostream& operator<<(std::ostream &out, const bn128_GT &g) +{ +#ifndef BINARY_OUTPUT + out << g.elem.a_ << OUTPUT_SEPARATOR << g.elem.b_; +#else + out.write((char*) &g.elem.a_, sizeof(g.elem.a_)); + out.write((char*) &g.elem.b_, sizeof(g.elem.b_)); +#endif + return out; +} + +std::istream& operator>>(std::istream &in, bn128_GT &g) +{ +#ifndef BINARY_OUTPUT + in >> g.elem.a_; + consume_OUTPUT_SEPARATOR(in); + in >> g.elem.b_; +#else + in.read((char*) &g.elem.a_, sizeof(g.elem.a_)); + in.read((char*) &g.elem.b_, sizeof(g.elem.b_)); +#endif + return in; +} +} // libsnark diff --git a/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/bn128/bn128_gt.hpp b/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/bn128/bn128_gt.hpp new file mode 100644 index 0000000..bc08fa1 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/bn128/bn128_gt.hpp @@ -0,0 +1,55 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef BN128_GT_HPP_ +#define BN128_GT_HPP_ +#include "algebra/fields/fp.hpp" +#include "algebra/fields/field_utils.hpp" +#include +#include "bn.h" + +namespace libsnark { + +class bn128_GT; +std::ostream& operator<<(std::ostream &, const bn128_GT&); +std::istream& operator>>(std::istream &, bn128_GT&); + +class bn128_GT { +public: + static bn128_GT GT_one; + bn::Fp12 elem; + + bn128_GT(); + bool operator==(const bn128_GT &other) const; + bool operator!=(const bn128_GT &other) const; + + bn128_GT operator*(const bn128_GT &other) const; + bn128_GT unitary_inverse() const; + + static bn128_GT one(); + + void print() { std::cout << this->elem << "\n"; }; + + friend std::ostream& operator<<(std::ostream &out, const bn128_GT &g); + friend std::istream& operator>>(std::istream &in, bn128_GT &g); +}; + +template +bn128_GT operator^(const bn128_GT &rhs, const bigint &lhs) +{ + return power(rhs, lhs); +} + + +template& modulus_p> +bn128_GT operator^(const bn128_GT &rhs, const Fp_model &lhs) +{ + return power(rhs, lhs.as_bigint()); +} + +} // libsnark +#endif // BN128_GT_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/bn128/bn128_init.cpp b/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/bn128/bn128_init.cpp new file mode 100644 index 0000000..d9c005a --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/bn128/bn128_init.cpp @@ -0,0 +1,226 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include "algebra/curves/bn128/bn128_init.hpp" +#include "algebra/curves/bn128/bn128_g1.hpp" +#include "algebra/curves/bn128/bn128_g2.hpp" +#include "algebra/curves/bn128/bn128_gt.hpp" + +namespace libsnark { + +bigint bn128_modulus_r; +bigint bn128_modulus_q; + +bn::Fp bn128_coeff_b; +size_t bn128_Fq_s; +bn::Fp bn128_Fq_nqr_to_t; +mie::Vuint bn128_Fq_t_minus_1_over_2; + +bn::Fp2 bn128_twist_coeff_b; +size_t bn128_Fq2_s; +bn::Fp2 bn128_Fq2_nqr_to_t; +mie::Vuint bn128_Fq2_t_minus_1_over_2; + +void init_bn128_params() +{ + bn::Param::init(); // init ate-pairing library + + typedef bigint bigint_r; + typedef bigint bigint_q; + + assert(sizeof(mp_limb_t) == 8 || sizeof(mp_limb_t) == 4); // Montgomery assumes this + + /* parameters for scalar field Fr */ + bn128_modulus_r = bigint_r("21888242871839275222246405745257275088548364400416034343698204186575808495617"); + assert(bn128_Fr::modulus_is_valid()); + if (sizeof(mp_limb_t) == 8) + { + bn128_Fr::Rsquared = bigint_r("944936681149208446651664254269745548490766851729442924617792859073125903783"); + bn128_Fr::Rcubed = bigint_r("5866548545943845227489894872040244720403868105578784105281690076696998248512"); + bn128_Fr::inv = 0xc2e1f593efffffff; + } + if (sizeof(mp_limb_t) == 4) + { + bn128_Fr::Rsquared = bigint_r("944936681149208446651664254269745548490766851729442924617792859073125903783"); + bn128_Fr::Rcubed = bigint_r("5866548545943845227489894872040244720403868105578784105281690076696998248512"); + bn128_Fr::inv = 0xefffffff; + } + bn128_Fr::num_bits = 254; + bn128_Fr::euler = bigint_r("10944121435919637611123202872628637544274182200208017171849102093287904247808"); + bn128_Fr::s = 28; + bn128_Fr::t = bigint_r("81540058820840996586704275553141814055101440848469862132140264610111"); + bn128_Fr::t_minus_1_over_2 = bigint_r("40770029410420498293352137776570907027550720424234931066070132305055"); + bn128_Fr::multiplicative_generator = bn128_Fr("5"); + bn128_Fr::root_of_unity = bn128_Fr("19103219067921713944291392827692070036145651957329286315305642004821462161904"); + bn128_Fr::nqr = bn128_Fr("5"); + bn128_Fr::nqr_to_t = bn128_Fr("19103219067921713944291392827692070036145651957329286315305642004821462161904"); + + /* parameters for base field Fq */ + bn128_modulus_q = bigint_q("21888242871839275222246405745257275088696311157297823662689037894645226208583"); + assert(bn128_Fq::modulus_is_valid()); + if (sizeof(mp_limb_t) == 8) + { + bn128_Fq::Rsquared = bigint_q("3096616502983703923843567936837374451735540968419076528771170197431451843209"); + bn128_Fq::Rcubed = bigint_q("14921786541159648185948152738563080959093619838510245177710943249661917737183"); + bn128_Fq::inv = 0x87d20782e4866389; + } + if (sizeof(mp_limb_t) == 4) + { + bn128_Fq::Rsquared = bigint_q("3096616502983703923843567936837374451735540968419076528771170197431451843209"); + bn128_Fq::Rcubed = bigint_q("14921786541159648185948152738563080959093619838510245177710943249661917737183"); + bn128_Fq::inv = 0xe4866389; + } + bn128_Fq::num_bits = 254; + bn128_Fq::euler = bigint_q("10944121435919637611123202872628637544348155578648911831344518947322613104291"); + bn128_Fq::s = 1; + bn128_Fq::t = bigint_q("10944121435919637611123202872628637544348155578648911831344518947322613104291"); + bn128_Fq::t_minus_1_over_2 = bigint_q("5472060717959818805561601436314318772174077789324455915672259473661306552145"); + bn128_Fq::multiplicative_generator = bn128_Fq("3"); + bn128_Fq::root_of_unity = bn128_Fq("21888242871839275222246405745257275088696311157297823662689037894645226208582"); + bn128_Fq::nqr = bn128_Fq("3"); + bn128_Fq::nqr_to_t = bn128_Fq("21888242871839275222246405745257275088696311157297823662689037894645226208582"); + + /* additional parameters for square roots in Fq/Fq2 */ + bn128_coeff_b = bn::Fp(3); + bn128_Fq_s = 1; + bn128_Fq_nqr_to_t = bn::Fp("21888242871839275222246405745257275088696311157297823662689037894645226208582"); + bn128_Fq_t_minus_1_over_2 = mie::Vuint("5472060717959818805561601436314318772174077789324455915672259473661306552145"); + + bn128_twist_coeff_b = bn::Fp2(bn::Fp("19485874751759354771024239261021720505790618469301721065564631296452457478373"), + bn::Fp("266929791119991161246907387137283842545076965332900288569378510910307636690")); + bn128_Fq2_s = 4; + bn128_Fq2_nqr_to_t = bn::Fp2(bn::Fp("5033503716262624267312492558379982687175200734934877598599011485707452665730"), + bn::Fp("314498342015008975724433667930697407966947188435857772134235984660852259084")); + bn128_Fq2_t_minus_1_over_2 = mie::Vuint("14971724250519463826312126413021210649976634891596900701138993820439690427699319920245032869357433499099632259837909383182382988566862092145199781964621"); + + /* choice of group G1 */ + bn128_G1::G1_zero.coord[0] = bn::Fp(1); + bn128_G1::G1_zero.coord[1] = bn::Fp(1); + bn128_G1::G1_zero.coord[2] = bn::Fp(0); + + bn128_G1::G1_one.coord[0] = bn::Fp(1); + bn128_G1::G1_one.coord[1] = bn::Fp(2); + bn128_G1::G1_one.coord[2] = bn::Fp(1); + + bn128_G1::wnaf_window_table.resize(0); + bn128_G1::wnaf_window_table.push_back(10); + bn128_G1::wnaf_window_table.push_back(24); + bn128_G1::wnaf_window_table.push_back(40); + bn128_G1::wnaf_window_table.push_back(132); + + bn128_G1::fixed_base_exp_window_table.resize(0); + // window 1 is unbeaten in [-inf, 4.24] + bn128_G1::fixed_base_exp_window_table.push_back(1); + // window 2 is unbeaten in [4.24, 10.43] + bn128_G1::fixed_base_exp_window_table.push_back(4); + // window 3 is unbeaten in [10.43, 24.88] + bn128_G1::fixed_base_exp_window_table.push_back(10); + // window 4 is unbeaten in [24.88, 62.10] + bn128_G1::fixed_base_exp_window_table.push_back(25); + // window 5 is unbeaten in [62.10, 157.80] + bn128_G1::fixed_base_exp_window_table.push_back(62); + // window 6 is unbeaten in [157.80, 362.05] + bn128_G1::fixed_base_exp_window_table.push_back(158); + // window 7 is unbeaten in [362.05, 806.67] + bn128_G1::fixed_base_exp_window_table.push_back(362); + // window 8 is unbeaten in [806.67, 2090.34] + bn128_G1::fixed_base_exp_window_table.push_back(807); + // window 9 is unbeaten in [2090.34, 4459.58] + bn128_G1::fixed_base_exp_window_table.push_back(2090); + // window 10 is unbeaten in [4459.58, 9280.12] + bn128_G1::fixed_base_exp_window_table.push_back(4460); + // window 11 is unbeaten in [9280.12, 43302.64] + bn128_G1::fixed_base_exp_window_table.push_back(9280); + // window 12 is unbeaten in [43302.64, 210998.73] + bn128_G1::fixed_base_exp_window_table.push_back(43303); + // window 13 is never the best + bn128_G1::fixed_base_exp_window_table.push_back(0); + // window 14 is never the best + bn128_G1::fixed_base_exp_window_table.push_back(0); + // window 15 is unbeaten in [210998.73, 506869.47] + bn128_G1::fixed_base_exp_window_table.push_back(210999); + // window 16 is unbeaten in [506869.47, 930023.36] + bn128_G1::fixed_base_exp_window_table.push_back(506869); + // window 17 is unbeaten in [930023.36, 8350812.20] + bn128_G1::fixed_base_exp_window_table.push_back(930023); + // window 18 is never the best + bn128_G1::fixed_base_exp_window_table.push_back(0); + // window 19 is never the best + bn128_G1::fixed_base_exp_window_table.push_back(0); + // window 20 is unbeaten in [8350812.20, 21708138.87] + bn128_G1::fixed_base_exp_window_table.push_back(8350812); + // window 21 is unbeaten in [21708138.87, 29482995.52] + bn128_G1::fixed_base_exp_window_table.push_back(21708139); + // window 22 is unbeaten in [29482995.52, inf] + bn128_G1::fixed_base_exp_window_table.push_back(29482996); + + /* choice of group G2 */ + bn128_G2::G2_zero.coord[0] = bn::Fp2(bn::Fp(1), bn::Fp(0)); + bn128_G2::G2_zero.coord[1] = bn::Fp2(bn::Fp(1), bn::Fp(0)); + bn128_G2::G2_zero.coord[2] = bn::Fp2(bn::Fp(0), bn::Fp(0)); + + bn128_G2::G2_one.coord[0] = bn::Fp2(bn::Fp("15267802884793550383558706039165621050290089775961208824303765753922461897946"), + bn::Fp("9034493566019742339402378670461897774509967669562610788113215988055021632533")); + bn128_G2::G2_one.coord[1] = bn::Fp2(bn::Fp("644888581738283025171396578091639672120333224302184904896215738366765861164"), + bn::Fp("20532875081203448695448744255224543661959516361327385779878476709582931298750")); + bn128_G2::G2_one.coord[2] = bn::Fp2(bn::Fp(1), bn::Fp(0)); + + bn128_G2::wnaf_window_table.resize(0); + bn128_G2::wnaf_window_table.push_back(7); + bn128_G2::wnaf_window_table.push_back(18); + bn128_G2::wnaf_window_table.push_back(35); + bn128_G2::wnaf_window_table.push_back(116); + + bn128_G2::fixed_base_exp_window_table.resize(0); + // window 1 is unbeaten in [-inf, 4.13] + bn128_G2::fixed_base_exp_window_table.push_back(1); + // window 2 is unbeaten in [4.13, 10.72] + bn128_G2::fixed_base_exp_window_table.push_back(4); + // window 3 is unbeaten in [10.72, 25.60] + bn128_G2::fixed_base_exp_window_table.push_back(11); + // window 4 is unbeaten in [25.60, 60.99] + bn128_G2::fixed_base_exp_window_table.push_back(26); + // window 5 is unbeaten in [60.99, 153.66] + bn128_G2::fixed_base_exp_window_table.push_back(61); + // window 6 is unbeaten in [153.66, 353.13] + bn128_G2::fixed_base_exp_window_table.push_back(154); + // window 7 is unbeaten in [353.13, 771.87] + bn128_G2::fixed_base_exp_window_table.push_back(353); + // window 8 is unbeaten in [771.87, 2025.85] + bn128_G2::fixed_base_exp_window_table.push_back(772); + // window 9 is unbeaten in [2025.85, 4398.65] + bn128_G2::fixed_base_exp_window_table.push_back(2026); + // window 10 is unbeaten in [4398.65, 10493.42] + bn128_G2::fixed_base_exp_window_table.push_back(4399); + // window 11 is unbeaten in [10493.42, 37054.73] + bn128_G2::fixed_base_exp_window_table.push_back(10493); + // window 12 is unbeaten in [37054.73, 49928.78] + bn128_G2::fixed_base_exp_window_table.push_back(37055); + // window 13 is unbeaten in [49928.78, 114502.82] + bn128_G2::fixed_base_exp_window_table.push_back(49929); + // window 14 is unbeaten in [114502.82, 161445.26] + bn128_G2::fixed_base_exp_window_table.push_back(114503); + // window 15 is unbeaten in [161445.26, 470648.01] + bn128_G2::fixed_base_exp_window_table.push_back(161445); + // window 16 is unbeaten in [470648.01, 1059821.87] + bn128_G2::fixed_base_exp_window_table.push_back(470648); + // window 17 is unbeaten in [1059821.87, 5450848.25] + bn128_G2::fixed_base_exp_window_table.push_back(1059822); + // window 18 is never the best + bn128_G2::fixed_base_exp_window_table.push_back(0); + // window 19 is unbeaten in [5450848.25, 5566795.57] + bn128_G2::fixed_base_exp_window_table.push_back(5450848); + // window 20 is unbeaten in [5566795.57, 33055217.52] + bn128_G2::fixed_base_exp_window_table.push_back(5566796); + // window 21 is never the best + bn128_G2::fixed_base_exp_window_table.push_back(0); + // window 22 is unbeaten in [33055217.52, inf] + bn128_G2::fixed_base_exp_window_table.push_back(33055218); + + bn128_GT::GT_one.elem = bn::Fp12(1); +} +} // libsnark diff --git a/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/bn128/bn128_init.hpp b/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/bn128/bn128_init.hpp new file mode 100644 index 0000000..ddb5c62 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/bn128/bn128_init.hpp @@ -0,0 +1,46 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef BN128_INIT_HPP_ +#define BN128_INIT_HPP_ +#include "algebra/curves/public_params.hpp" +#include "algebra/fields/fp.hpp" +#include "bn.h" // If you're missing this file, run libsnark's ./prepare-depends.sh + +namespace libsnark { + +const mp_size_t bn128_r_bitcount = 254; +const mp_size_t bn128_q_bitcount = 254; + +const mp_size_t bn128_r_limbs = (bn128_r_bitcount+GMP_NUMB_BITS-1)/GMP_NUMB_BITS; +const mp_size_t bn128_q_limbs = (bn128_q_bitcount+GMP_NUMB_BITS-1)/GMP_NUMB_BITS; + +extern bigint bn128_modulus_r; +extern bigint bn128_modulus_q; + +extern bn::Fp bn128_coeff_b; +extern size_t bn128_Fq_s; +extern bn::Fp bn128_Fq_nqr_to_t; +extern mie::Vuint bn128_Fq_t_minus_1_over_2; + +extern bn::Fp2 bn128_twist_coeff_b; +extern size_t bn128_Fq2_s; +extern bn::Fp2 bn128_Fq2_nqr_to_t; +extern mie::Vuint bn128_Fq2_t_minus_1_over_2; + +typedef Fp_model bn128_Fr; +typedef Fp_model bn128_Fq; + +void init_bn128_params(); + +class bn128_G1; +class bn128_G2; +class bn128_GT; +typedef bn128_GT bn128_Fq12; + +} // libsnark +#endif // BN128_INIT_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/bn128/bn128_pairing.cpp b/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/bn128/bn128_pairing.cpp new file mode 100644 index 0000000..ac4290a --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/bn128/bn128_pairing.cpp @@ -0,0 +1,212 @@ +/** @file + ******************************************************************************** + Implements functions for computing Ate pairings over the bn128 curves, split into a + offline and online stages. + ******************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *******************************************************************************/ + +#include + +#include "algebra/curves/bn128/bn128_pairing.hpp" +#include "common/profiling.hpp" +#include "algebra/curves/bn128/bn128_init.hpp" +#include "algebra/curves/bn128/bn128_g1.hpp" +#include "algebra/curves/bn128/bn128_g2.hpp" +#include "algebra/curves/bn128/bn128_gt.hpp" + +namespace libsnark { + +bool bn128_ate_G1_precomp::operator==(const bn128_ate_G1_precomp &other) const +{ + return (this->P[0] == other.P[0] && + this->P[1] == other.P[1] && + this->P[2] == other.P[2]); +} + +std::ostream& operator<<(std::ostream &out, const bn128_ate_G1_precomp &prec_P) +{ + for (size_t i = 0; i < 3; ++i) + { +#ifndef BINARY_OUTPUT + out << prec_P.P[i] << "\n"; +#else + out.write((char*) &prec_P.P[i], sizeof(prec_P.P[i])); +#endif + } + return out; +} + +std::istream& operator>>(std::istream &in, bn128_ate_G1_precomp &prec_P) +{ + for (size_t i = 0; i < 3; ++i) + { +#ifndef BINARY_OUTPUT + in >> prec_P.P[i]; + consume_newline(in); +#else + in.read((char*) &prec_P.P[i], sizeof(prec_P.P[i])); +#endif + } + return in; +} + +bool bn128_ate_G2_precomp::operator==(const bn128_ate_G2_precomp &other) const +{ + if (!(this->Q[0] == other.Q[0] && + this->Q[1] == other.Q[1] && + this->Q[2] == other.Q[2] && + this->coeffs.size() == other.coeffs.size())) + { + return false; + } + + /* work around for upstream serialization bug */ + for (size_t i = 0; i < this->coeffs.size(); ++i) + { + std::stringstream this_ss, other_ss; + this_ss << this->coeffs[i]; + other_ss << other.coeffs[i]; + if (this_ss.str() != other_ss.str()) + { + return false; + } + } + + return true; +} + +std::ostream& operator<<(std::ostream &out, const bn128_ate_G2_precomp &prec_Q) +{ + for (size_t i = 0; i < 3; ++i) + { +#ifndef BINARY_OUTPUT + out << prec_Q.Q[i].a_ << "\n"; + out << prec_Q.Q[i].b_ << "\n"; +#else + out.write((char*) &prec_Q.Q[i].a_, sizeof(prec_Q.Q[i].a_)); + out.write((char*) &prec_Q.Q[i].b_, sizeof(prec_Q.Q[i].b_)); +#endif + } + + out << prec_Q.coeffs.size() << "\n"; + + for (size_t i = 0; i < prec_Q.coeffs.size(); ++i) + { +#ifndef BINARY_OUTPUT + out << prec_Q.coeffs[i].a_.a_ << "\n"; + out << prec_Q.coeffs[i].a_.b_ << "\n"; + out << prec_Q.coeffs[i].b_.a_ << "\n"; + out << prec_Q.coeffs[i].b_.b_ << "\n"; + out << prec_Q.coeffs[i].c_.a_ << "\n"; + out << prec_Q.coeffs[i].c_.b_ << "\n"; +#else + out.write((char*) &prec_Q.coeffs[i].a_.a_, sizeof(prec_Q.coeffs[i].a_.a_)); + out.write((char*) &prec_Q.coeffs[i].a_.b_, sizeof(prec_Q.coeffs[i].a_.b_)); + out.write((char*) &prec_Q.coeffs[i].b_.a_, sizeof(prec_Q.coeffs[i].b_.a_)); + out.write((char*) &prec_Q.coeffs[i].b_.b_, sizeof(prec_Q.coeffs[i].b_.b_)); + out.write((char*) &prec_Q.coeffs[i].c_.a_, sizeof(prec_Q.coeffs[i].c_.a_)); + out.write((char*) &prec_Q.coeffs[i].c_.b_, sizeof(prec_Q.coeffs[i].c_.b_)); +#endif + } + + return out; +} + +std::istream& operator>>(std::istream &in, bn128_ate_G2_precomp &prec_Q) +{ + for (size_t i = 0; i < 3; ++i) + { +#ifndef BINARY_OUTPUT + in >> prec_Q.Q[i].a_; + consume_newline(in); + in >> prec_Q.Q[i].b_; + consume_newline(in); +#else + in.read((char*) &prec_Q.Q[i].a_, sizeof(prec_Q.Q[i].a_)); + in.read((char*) &prec_Q.Q[i].b_, sizeof(prec_Q.Q[i].b_)); +#endif + } + + size_t count; + in >> count; + consume_newline(in); + prec_Q.coeffs.resize(count); + for (size_t i = 0; i < count; ++i) + { +#ifndef BINARY_OUTPUT + in >> prec_Q.coeffs[i].a_.a_; + consume_newline(in); + in >> prec_Q.coeffs[i].a_.b_; + consume_newline(in); + in >> prec_Q.coeffs[i].b_.a_; + consume_newline(in); + in >> prec_Q.coeffs[i].b_.b_; + consume_newline(in); + in >> prec_Q.coeffs[i].c_.a_; + consume_newline(in); + in >> prec_Q.coeffs[i].c_.b_; + consume_newline(in); +#else + in.read((char*) &prec_Q.coeffs[i].a_.a_, sizeof(prec_Q.coeffs[i].a_.a_)); + in.read((char*) &prec_Q.coeffs[i].a_.b_, sizeof(prec_Q.coeffs[i].a_.b_)); + in.read((char*) &prec_Q.coeffs[i].b_.a_, sizeof(prec_Q.coeffs[i].b_.a_)); + in.read((char*) &prec_Q.coeffs[i].b_.b_, sizeof(prec_Q.coeffs[i].b_.b_)); + in.read((char*) &prec_Q.coeffs[i].c_.a_, sizeof(prec_Q.coeffs[i].c_.a_)); + in.read((char*) &prec_Q.coeffs[i].c_.b_, sizeof(prec_Q.coeffs[i].c_.b_)); +#endif + } + return in; +} + +bn128_ate_G1_precomp bn128_ate_precompute_G1(const bn128_G1& P) +{ + enter_block("Call to bn128_ate_precompute_G1"); + + bn128_ate_G1_precomp result; + bn::ecop::NormalizeJac(result.P, P.coord); + + leave_block("Call to bn128_ate_precompute_G1"); + return result; +} + +bn128_ate_G2_precomp bn128_ate_precompute_G2(const bn128_G2& Q) +{ + enter_block("Call to bn128_ate_precompute_G2"); + + bn128_ate_G2_precomp result; + bn::components::precomputeG2(result.coeffs, result.Q, Q.coord); + + leave_block("Call to bn128_ate_precompute_G2"); + return result; +} + +bn128_Fq12 bn128_ate_miller_loop(const bn128_ate_G1_precomp &prec_P, + const bn128_ate_G2_precomp &prec_Q) +{ + bn128_Fq12 f; + bn::components::millerLoop(f.elem, prec_Q.coeffs, prec_P.P); + return f; +} + +bn128_Fq12 bn128_double_ate_miller_loop(const bn128_ate_G1_precomp &prec_P1, + const bn128_ate_G2_precomp &prec_Q1, + const bn128_ate_G1_precomp &prec_P2, + const bn128_ate_G2_precomp &prec_Q2) +{ + bn128_Fq12 f; + bn::components::millerLoop2(f.elem, prec_Q1.coeffs, prec_P1.P, prec_Q2.coeffs, prec_P2.P); + return f; +} + +bn128_GT bn128_final_exponentiation(const bn128_Fq12 &elt) +{ + enter_block("Call to bn128_final_exponentiation"); + bn128_GT eltcopy = elt; + eltcopy.elem.final_exp(); + leave_block("Call to bn128_final_exponentiation"); + return eltcopy; +} +} // libsnark diff --git a/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/bn128/bn128_pairing.hpp b/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/bn128/bn128_pairing.hpp new file mode 100644 index 0000000..f639d0a --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/bn128/bn128_pairing.hpp @@ -0,0 +1,52 @@ +/** @file + ******************************************************************************** + Declares functions for computing Ate pairings over the bn128 curves, split into a + offline and online stages. + ******************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *******************************************************************************/ + +#ifndef BN128_PAIRING_HPP_ +#define BN128_PAIRING_HPP_ +#include "algebra/curves/bn128/bn128_g1.hpp" +#include "algebra/curves/bn128/bn128_g2.hpp" +#include "algebra/curves/bn128/bn128_gt.hpp" +#include "bn.h" + +namespace libsnark { + +struct bn128_ate_G1_precomp { + bn::Fp P[3]; + + bool operator==(const bn128_ate_G1_precomp &other) const; + friend std::ostream& operator<<(std::ostream &out, const bn128_ate_G1_precomp &prec_P); + friend std::istream& operator>>(std::istream &in, bn128_ate_G1_precomp &prec_P); +}; + +typedef bn::Fp6 bn128_ate_ell_coeffs; + +struct bn128_ate_G2_precomp { + bn::Fp2 Q[3]; + std::vector coeffs; + + bool operator==(const bn128_ate_G2_precomp &other) const; + friend std::ostream& operator<<(std::ostream &out, const bn128_ate_G2_precomp &prec_Q); + friend std::istream& operator>>(std::istream &in, bn128_ate_G2_precomp &prec_Q); +}; + +bn128_ate_G1_precomp bn128_ate_precompute_G1(const bn128_G1& P); +bn128_ate_G2_precomp bn128_ate_precompute_G2(const bn128_G2& Q); + +bn128_Fq12 bn128_double_ate_miller_loop(const bn128_ate_G1_precomp &prec_P1, + const bn128_ate_G2_precomp &prec_Q1, + const bn128_ate_G1_precomp &prec_P2, + const bn128_ate_G2_precomp &prec_Q2); +bn128_Fq12 bn128_ate_miller_loop(const bn128_ate_G1_precomp &prec_P, + const bn128_ate_G2_precomp &prec_Q); + +bn128_GT bn128_final_exponentiation(const bn128_Fq12 &elt); + +} // libsnark +#endif // BN128_PAIRING_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/bn128/bn128_pp.cpp b/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/bn128/bn128_pp.cpp new file mode 100644 index 0000000..6557f04 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/bn128/bn128_pp.cpp @@ -0,0 +1,75 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include "algebra/curves/bn128/bn128_pp.hpp" +#include "common/profiling.hpp" + +namespace libsnark { + +void bn128_pp::init_public_params() +{ + init_bn128_params(); +} + +bn128_GT bn128_pp::final_exponentiation(const bn128_GT &elt) +{ + return bn128_final_exponentiation(elt); +} + +bn128_ate_G1_precomp bn128_pp::precompute_G1(const bn128_G1 &P) +{ + return bn128_ate_precompute_G1(P); +} + +bn128_ate_G2_precomp bn128_pp::precompute_G2(const bn128_G2 &Q) +{ + return bn128_ate_precompute_G2(Q); +} + +bn128_Fq12 bn128_pp::miller_loop(const bn128_ate_G1_precomp &prec_P, + const bn128_ate_G2_precomp &prec_Q) +{ + enter_block("Call to miller_loop"); + bn128_Fq12 result = bn128_ate_miller_loop(prec_P, prec_Q); + leave_block("Call to miller_loop"); + return result; +} + +bn128_Fq12 bn128_pp::double_miller_loop(const bn128_ate_G1_precomp &prec_P1, + const bn128_ate_G2_precomp &prec_Q1, + const bn128_ate_G1_precomp &prec_P2, + const bn128_ate_G2_precomp &prec_Q2) +{ + enter_block("Call to double_miller_loop"); + bn128_Fq12 result = bn128_double_ate_miller_loop(prec_P1, prec_Q1, prec_P2, prec_Q2); + leave_block("Call to double_miller_loop"); + return result; +} + +bn128_Fq12 bn128_pp::pairing(const bn128_G1 &P, + const bn128_G2 &Q) +{ + enter_block("Call to pairing"); + bn128_ate_G1_precomp prec_P = bn128_pp::precompute_G1(P); + bn128_ate_G2_precomp prec_Q = bn128_pp::precompute_G2(Q); + + bn128_Fq12 result = bn128_pp::miller_loop(prec_P, prec_Q); + leave_block("Call to pairing"); + return result; +} + +bn128_GT bn128_pp::reduced_pairing(const bn128_G1 &P, + const bn128_G2 &Q) +{ + enter_block("Call to reduced_pairing"); + const bn128_Fq12 f = bn128_pp::pairing(P, Q); + const bn128_GT result = bn128_pp::final_exponentiation(f); + leave_block("Call to reduced_pairing"); + return result; +} + +} // libsnark diff --git a/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/bn128/bn128_pp.hpp b/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/bn128/bn128_pp.hpp new file mode 100644 index 0000000..dfd1c6b --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/bn128/bn128_pp.hpp @@ -0,0 +1,51 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef BN128_PP_HPP_ +#define BN128_PP_HPP_ +#include "algebra/curves/public_params.hpp" +#include "algebra/curves/bn128/bn128_init.hpp" +#include "algebra/curves/bn128/bn128_g1.hpp" +#include "algebra/curves/bn128/bn128_g2.hpp" +#include "algebra/curves/bn128/bn128_gt.hpp" +#include "algebra/curves/bn128/bn128_pairing.hpp" + +namespace libsnark { + +class bn128_pp { +public: + typedef bn128_Fr Fp_type; + typedef bn128_G1 G1_type; + typedef bn128_G2 G2_type; + typedef bn128_ate_G1_precomp G1_precomp_type; + typedef bn128_ate_G2_precomp G2_precomp_type; + typedef bn128_Fq Fq_type; + typedef bn128_Fq12 Fqk_type; + typedef bn128_GT GT_type; + + static const bool has_affine_pairing = false; + + static void init_public_params(); + static bn128_GT final_exponentiation(const bn128_Fq12 &elt); + static bn128_ate_G1_precomp precompute_G1(const bn128_G1 &P); + static bn128_ate_G2_precomp precompute_G2(const bn128_G2 &Q); + static bn128_Fq12 miller_loop(const bn128_ate_G1_precomp &prec_P, + const bn128_ate_G2_precomp &prec_Q); + static bn128_Fq12 double_miller_loop(const bn128_ate_G1_precomp &prec_P1, + const bn128_ate_G2_precomp &prec_Q1, + const bn128_ate_G1_precomp &prec_P2, + const bn128_ate_G2_precomp &prec_Q2); + + /* the following are used in test files */ + static bn128_GT pairing(const bn128_G1 &P, + const bn128_G2 &Q); + static bn128_GT reduced_pairing(const bn128_G1 &P, + const bn128_G2 &Q); +}; + +} // libsnark +#endif // BN128_PP_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/bn128/bn_utils.hpp b/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/bn128/bn_utils.hpp new file mode 100644 index 0000000..d6caf43 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/bn128/bn_utils.hpp @@ -0,0 +1,22 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef BN_UTILS_HPP_ +#define BN_UTILS_HPP_ +#include +#include "bn.h" + +namespace libsnark { + +template +void bn_batch_invert(std::vector &vec); + +} // libsnark + +#include "algebra/curves/bn128/bn_utils.tcc" + +#endif // BN_UTILS_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/bn128/bn_utils.tcc b/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/bn128/bn_utils.tcc new file mode 100644 index 0000000..931dac4 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/bn128/bn_utils.tcc @@ -0,0 +1,40 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef BN_UTILS_TCC_ +#define BN_UTILS_TCC_ + +namespace libsnark { + +template +void bn_batch_invert(std::vector &vec) +{ + std::vector prod; + prod.reserve(vec.size()); + + FieldT acc = 1; + + for (auto el : vec) + { + assert(!el.isZero()); + prod.emplace_back(acc); + FieldT::mul(acc, acc, el); + } + + FieldT acc_inverse = acc; + acc_inverse.inverse(); + + for (long i = vec.size()-1; i >= 0; --i) + { + const FieldT old_el = vec[i]; + FieldT::mul(vec[i], acc_inverse, prod[i]); + FieldT::mul(acc_inverse, acc_inverse, old_el); + } +} + +} // libsnark +#endif // FIELD_UTILS_TCC_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/curve_utils.hpp b/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/curve_utils.hpp new file mode 100644 index 0000000..33a8e1e --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/curve_utils.hpp @@ -0,0 +1,22 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef CURVE_UTILS_HPP_ +#define CURVE_UTILS_HPP_ +#include + +#include "algebra/fields/bigint.hpp" + +namespace libsnark { + +template +GroupT scalar_mul(const GroupT &base, const bigint &scalar); + +} // libsnark +#include "algebra/curves/curve_utils.tcc" + +#endif // CURVE_UTILS_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/curve_utils.tcc b/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/curve_utils.tcc new file mode 100644 index 0000000..251d75d --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/curve_utils.tcc @@ -0,0 +1,37 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef CURVE_UTILS_TCC_ +#define CURVE_UTILS_TCC_ + +namespace libsnark { + +template +GroupT scalar_mul(const GroupT &base, const bigint &scalar) +{ + GroupT result = GroupT::zero(); + + bool found_one = false; + for (long i = scalar.max_bits() - 1; i >= 0; --i) + { + if (found_one) + { + result = result.dbl(); + } + + if (scalar.test_bit(i)) + { + found_one = true; + result = result + base; + } + } + + return result; +} + +} // libsnark +#endif // CURVE_UTILS_TCC_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/edwards/edwards_g1.cpp b/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/edwards/edwards_g1.cpp new file mode 100644 index 0000000..7d507fe --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/edwards/edwards_g1.cpp @@ -0,0 +1,413 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include "algebra/curves/edwards/edwards_g1.hpp" + +namespace libsnark { + +#ifdef PROFILE_OP_COUNTS +long long edwards_G1::add_cnt = 0; +long long edwards_G1::dbl_cnt = 0; +#endif + +std::vector edwards_G1::wnaf_window_table; +std::vector edwards_G1::fixed_base_exp_window_table; +edwards_G1 edwards_G1::G1_zero; +edwards_G1 edwards_G1::G1_one; + +edwards_G1::edwards_G1() +{ + this->X = G1_zero.X; + this->Y = G1_zero.Y; + this->Z = G1_zero.Z; +} + +void edwards_G1::print() const +{ + if (this->is_zero()) + { + printf("O\n"); + } + else + { + edwards_G1 copy(*this); + copy.to_affine_coordinates(); + gmp_printf("(%Nd , %Nd)\n", + copy.X.as_bigint().data, edwards_Fq::num_limbs, + copy.Y.as_bigint().data, edwards_Fq::num_limbs); + } +} + +void edwards_G1::print_coordinates() const +{ + if (this->is_zero()) + { + printf("O\n"); + } + else + { + gmp_printf("(%Nd : %Nd : %Nd)\n", + this->X.as_bigint().data, edwards_Fq::num_limbs, + this->Y.as_bigint().data, edwards_Fq::num_limbs, + this->Z.as_bigint().data, edwards_Fq::num_limbs); + } +} + +void edwards_G1::to_affine_coordinates() +{ + if (this->is_zero()) + { + this->X = edwards_Fq::zero(); + this->Y = edwards_Fq::one(); + this->Z = edwards_Fq::one(); + } + else + { + // go from inverted coordinates to projective coordinates + edwards_Fq tX = this->Y * this->Z; + edwards_Fq tY = this->X * this->Z; + edwards_Fq tZ = this->X * this->Y; + // go from projective coordinates to affine coordinates + edwards_Fq tZ_inv = tZ.inverse(); + this->X = tX * tZ_inv; + this->Y = tY * tZ_inv; + this->Z = edwards_Fq::one(); + } +} + +void edwards_G1::to_special() +{ + if (this->Z.is_zero()) + { + return; + } + +#ifdef DEBUG + const edwards_G1 copy(*this); +#endif + + edwards_Fq Z_inv = this->Z.inverse(); + this->X = this->X * Z_inv; + this->Y = this->Y * Z_inv; + this->Z = edwards_Fq::one(); + +#ifdef DEBUG + assert((*this) == copy); +#endif +} + +bool edwards_G1::is_special() const +{ + return (this->is_zero() || this->Z == edwards_Fq::one()); +} + +bool edwards_G1::is_zero() const +{ + return (this->Y.is_zero() && this->Z.is_zero()); +} + +bool edwards_G1::operator==(const edwards_G1 &other) const +{ + if (this->is_zero()) + { + return other.is_zero(); + } + + if (other.is_zero()) + { + return false; + } + + /* now neither is O */ + + // X1/Z1 = X2/Z2 <=> X1*Z2 = X2*Z1 + if ((this->X * other.Z) != (other.X * this->Z)) + { + return false; + } + + // Y1/Z1 = Y2/Z2 <=> Y1*Z2 = Y2*Z1 + if ((this->Y * other.Z) != (other.Y * this->Z)) + { + return false; + } + + return true; +} + +bool edwards_G1::operator!=(const edwards_G1& other) const +{ + return !(operator==(other)); +} + +edwards_G1 edwards_G1::operator+(const edwards_G1 &other) const +{ + // handle special cases having to do with O + if (this->is_zero()) + { + return other; + } + + if (other.is_zero()) + { + return (*this); + } + + return this->add(other); +} + +edwards_G1 edwards_G1::operator-() const +{ + return edwards_G1(-(this->X), this->Y, this->Z); +} + + +edwards_G1 edwards_G1::operator-(const edwards_G1 &other) const +{ + return (*this) + (-other); +} + +edwards_G1 edwards_G1::add(const edwards_G1 &other) const +{ +#ifdef PROFILE_OP_COUNTS + this->add_cnt++; +#endif + // NOTE: does not handle O and pts of order 2,4 + // http://www.hyperelliptic.org/EFD/g1p/auto-edwards-inverted.html#addition-add-2007-bl + + edwards_Fq A = (this->Z) * (other.Z); // A = Z1*Z2 + edwards_Fq B = edwards_coeff_d * A.squared(); // B = d*A^2 + edwards_Fq C = (this->X) * (other.X); // C = X1*X2 + edwards_Fq D = (this->Y) * (other.Y); // D = Y1*Y2 + edwards_Fq E = C * D; // E = C*D + edwards_Fq H = C - D; // H = C-D + edwards_Fq I = (this->X+this->Y)*(other.X+other.Y)-C-D; // I = (X1+Y1)*(X2+Y2)-C-D + edwards_Fq X3 = (E+B)*H; // X3 = c*(E+B)*H + edwards_Fq Y3 = (E-B)*I; // Y3 = c*(E-B)*I + edwards_Fq Z3 = A*H*I; // Z3 = A*H*I + + return edwards_G1(X3, Y3, Z3); +} + +edwards_G1 edwards_G1::mixed_add(const edwards_G1 &other) const +{ +#ifdef PROFILE_OP_COUNTS + this->add_cnt++; +#endif + // handle special cases having to do with O + if (this->is_zero()) + { + return other; + } + + if (other.is_zero()) + { + return *this; + } + +#ifdef DEBUG + assert(other.is_special()); +#endif + + // NOTE: does not handle O and pts of order 2,4 + // http://www.hyperelliptic.org/EFD/g1p/auto-edwards-inverted.html#addition-madd-2007-lb + + edwards_Fq A = this->Z; // A = Z1 + edwards_Fq B = edwards_coeff_d * A.squared(); // B = d*A^2 + edwards_Fq C = (this->X) * (other.X); // C = X1*X2 + edwards_Fq D = (this->Y) * (other.Y); // D = Y1*Y2 + edwards_Fq E = C * D; // E = C*D + edwards_Fq H = C - D; // H = C-D + edwards_Fq I = (this->X+this->Y)*(other.X+other.Y)-C-D; // I = (X1+Y1)*(X2+Y2)-C-D + edwards_Fq X3 = (E+B)*H; // X3 = c*(E+B)*H + edwards_Fq Y3 = (E-B)*I; // Y3 = c*(E-B)*I + edwards_Fq Z3 = A*H*I; // Z3 = A*H*I + + return edwards_G1(X3, Y3, Z3); +} + +edwards_G1 edwards_G1::dbl() const +{ +#ifdef PROFILE_OP_COUNTS + this->dbl_cnt++; +#endif + if (this->is_zero()) + { + return (*this); + } + else + { + // NOTE: does not handle O and pts of order 2,4 + // http://www.hyperelliptic.org/EFD/g1p/auto-edwards-inverted.html#doubling-dbl-2007-bl + + edwards_Fq A = (this->X).squared(); // A = X1^2 + edwards_Fq B = (this->Y).squared(); // B = Y1^2 + edwards_Fq C = A+B; // C = A+B + edwards_Fq D = A-B; // D = A-B + edwards_Fq E = (this->X+this->Y).squared()-C; // E = (X1+Y1)^2-C + edwards_Fq X3 = C*D; // X3 = C*D + edwards_Fq dZZ = edwards_coeff_d * this->Z.squared(); + edwards_Fq Y3 = E*(C-dZZ-dZZ); // Y3 = E*(C-2*d*Z1^2) + edwards_Fq Z3 = D*E; // Z3 = D*E + + return edwards_G1(X3, Y3, Z3); + } +} + +bool edwards_G1::is_well_formed() const +{ + /* Note that point at infinity is the only special case we must check as + inverted representation does no cover points (0, +-c) and (+-c, 0). */ + if (this->is_zero()) + { + return true; + } + else + { + /* + a x^2 + y^2 = 1 + d x^2 y^2 + + We are using inverted, so equation we need to check is actually + + a (z/x)^2 + (z/y)^2 = 1 + d z^4 / (x^2 * y^2) + z^2 (a y^2 + x^2 - dz^2) = x^2 y^2 + */ + edwards_Fq X2 = this->X.squared(); + edwards_Fq Y2 = this->Y.squared(); + edwards_Fq Z2 = this->Z.squared(); + + // for G1 a = 1 + return (Z2 * (Y2 + X2 - edwards_coeff_d * Z2) == X2 * Y2); + } +} + +edwards_G1 edwards_G1::zero() +{ + return G1_zero; +} + +edwards_G1 edwards_G1::one() +{ + return G1_one; +} + +edwards_G1 edwards_G1::random_element() +{ + return edwards_Fr::random_element().as_bigint() * G1_one; +} + +std::ostream& operator<<(std::ostream &out, const edwards_G1 &g) +{ + edwards_G1 copy(g); + copy.to_affine_coordinates(); +#ifdef NO_PT_COMPRESSION + out << copy.X << OUTPUT_SEPARATOR << copy.Y; +#else + /* storing LSB of Y */ + out << copy.X << OUTPUT_SEPARATOR << (copy.Y.as_bigint().data[0] & 1); +#endif + + return out; +} + +std::istream& operator>>(std::istream &in, edwards_G1 &g) +{ + edwards_Fq tX, tY; + +#ifdef NO_PT_COMPRESSION + in >> tX; + consume_OUTPUT_SEPARATOR(in); + in >> tY; +#else + /* + a x^2 + y^2 = 1 + d x^2 y^2 + y = sqrt((1-ax^2)/(1-dx^2)) + */ + unsigned char Y_lsb; + in >> tX; + + consume_OUTPUT_SEPARATOR(in); + in.read((char*)&Y_lsb, 1); + Y_lsb -= '0'; + + edwards_Fq tX2 = tX.squared(); + edwards_Fq tY2 = (edwards_Fq::one() - tX2) * // a = 1 for G1 (not a twist) + (edwards_Fq::one() - edwards_coeff_d * tX2).inverse(); + tY = tY2.sqrt(); + + if ((tY.as_bigint().data[0] & 1) != Y_lsb) + { + tY = -tY; + } +#endif + + // using inverted coordinates + g.X = tY; + g.Y = tX; + g.Z = tX * tY; + +#ifdef USE_MIXED_ADDITION + g.to_special(); +#endif + + return in; +} + +std::ostream& operator<<(std::ostream& out, const std::vector &v) +{ + out << v.size() << "\n"; + for (const edwards_G1& t : v) + { + out << t << OUTPUT_NEWLINE; + } + + return out; +} + +std::istream& operator>>(std::istream& in, std::vector &v) +{ + v.clear(); + + size_t s; + in >> s; + v.reserve(s); + consume_newline(in); + + for (size_t i = 0; i < s; ++i) + { + edwards_G1 g; + in >> g; + v.emplace_back(g); + consume_OUTPUT_NEWLINE(in); + } + + return in; +} + +template<> +void batch_to_special_all_non_zeros(std::vector &vec) +{ + std::vector Z_vec; + Z_vec.reserve(vec.size()); + + for (auto &el: vec) + { + Z_vec.emplace_back(el.Z); + } + batch_invert(Z_vec); + + const edwards_Fq one = edwards_Fq::one(); + + for (size_t i = 0; i < vec.size(); ++i) + { + vec[i].X = vec[i].X * Z_vec[i]; + vec[i].Y = vec[i].Y * Z_vec[i]; + vec[i].Z = one; + } +} + +} // libsnark diff --git a/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/edwards/edwards_g1.hpp b/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/edwards/edwards_g1.hpp new file mode 100644 index 0000000..27cb1a8 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/edwards/edwards_g1.hpp @@ -0,0 +1,97 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef EDWARDS_G1_HPP_ +#define EDWARDS_G1_HPP_ +#include +#include "algebra/curves/edwards/edwards_init.hpp" +#include "algebra/curves/curve_utils.hpp" + +namespace libsnark { + +class edwards_G1; +std::ostream& operator<<(std::ostream &, const edwards_G1&); +std::istream& operator>>(std::istream &, edwards_G1&); + +class edwards_G1 { +public: +#ifdef PROFILE_OP_COUNTS + static long long add_cnt; + static long long dbl_cnt; +#endif + static std::vector wnaf_window_table; + static std::vector fixed_base_exp_window_table; + static edwards_G1 G1_zero; + static edwards_G1 G1_one; + + edwards_Fq X, Y, Z; + edwards_G1(); +private: + edwards_G1(const edwards_Fq& X, const edwards_Fq& Y, const edwards_Fq& Z) : X(X), Y(Y), Z(Z) {}; + +public: + typedef edwards_Fq base_field; + typedef edwards_Fr scalar_field; + // using inverted coordinates + edwards_G1(const edwards_Fq& X, const edwards_Fq& Y) : X(Y), Y(X), Z(X*Y) {}; + + void print() const; + void print_coordinates() const; + + void to_affine_coordinates(); + void to_special(); + bool is_special() const; + + bool is_zero() const; + + bool operator==(const edwards_G1 &other) const; + bool operator!=(const edwards_G1 &other) const; + + edwards_G1 operator+(const edwards_G1 &other) const; + edwards_G1 operator-() const; + edwards_G1 operator-(const edwards_G1 &other) const; + + edwards_G1 add(const edwards_G1 &other) const; + edwards_G1 mixed_add(const edwards_G1 &other) const; + edwards_G1 dbl() const; + + bool is_well_formed() const; + + static edwards_G1 zero(); + static edwards_G1 one(); + static edwards_G1 random_element(); + + static size_t size_in_bits() { return edwards_Fq::size_in_bits() + 1; } + static bigint base_field_char() { return base_field::field_char(); } + static bigint order() { return scalar_field::field_char(); } + + friend std::ostream& operator<<(std::ostream &out, const edwards_G1 &g); + friend std::istream& operator>>(std::istream &in, edwards_G1 &g); +}; + +template +edwards_G1 operator*(const bigint &lhs, const edwards_G1 &rhs) +{ + return scalar_mul(rhs, lhs); +} + +template& modulus_p> +edwards_G1 operator*(const Fp_model &lhs, const edwards_G1 &rhs) +{ + return scalar_mul(rhs, lhs.as_bigint()); +} + +std::ostream& operator<<(std::ostream& out, const std::vector &v); +std::istream& operator>>(std::istream& in, std::vector &v); + +template +void batch_to_special_all_non_zeros(std::vector &vec); +template<> +void batch_to_special_all_non_zeros(std::vector &vec); + +} // libsnark +#endif // EDWARDS_G1_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/edwards/edwards_g2.cpp b/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/edwards/edwards_g2.cpp new file mode 100644 index 0000000..1880787 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/edwards/edwards_g2.cpp @@ -0,0 +1,416 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include "algebra/curves/edwards/edwards_g2.hpp" + +namespace libsnark { + +#ifdef PROFILE_OP_COUNTS +long long edwards_G2::add_cnt = 0; +long long edwards_G2::dbl_cnt = 0; +#endif + +std::vector edwards_G2::wnaf_window_table; +std::vector edwards_G2::fixed_base_exp_window_table; + +edwards_G2 edwards_G2::G2_zero; +edwards_G2 edwards_G2::G2_one; + +edwards_G2::edwards_G2() +{ + this->X = G2_zero.X; + this->Y = G2_zero.Y; + this->Z = G2_zero.Z; +} + +edwards_Fq3 edwards_G2::mul_by_a(const edwards_Fq3 &elt) +{ + // should be + // edwards_Fq3(edwards_twist_mul_by_a_c0 * elt.c2, edwards_twist_mul_by_a_c1 * elt.c0, edwards_twist_mul_by_a_c2 * elt.c1) + // but optimizing the fact that edwards_twist_mul_by_a_c1 = edwards_twist_mul_by_a_c2 = 1 + return edwards_Fq3(edwards_twist_mul_by_a_c0 * elt.c2, elt.c0, elt.c1); +} + +edwards_Fq3 edwards_G2::mul_by_d(const edwards_Fq3 &elt) +{ + return edwards_Fq3(edwards_twist_mul_by_d_c0 * elt.c2, edwards_twist_mul_by_d_c1 * elt.c0, edwards_twist_mul_by_d_c2 * elt.c1); +} + +void edwards_G2::print() const +{ + if (this->is_zero()) + { + printf("O\n"); + } + else + { + edwards_G2 copy(*this); + copy.to_affine_coordinates(); + gmp_printf("(%Nd*z^2 + %Nd*z + %Nd , %Nd*z^2 + %Nd*z + %Nd)\n", + copy.X.c2.as_bigint().data, edwards_Fq::num_limbs, + copy.X.c1.as_bigint().data, edwards_Fq::num_limbs, + copy.X.c0.as_bigint().data, edwards_Fq::num_limbs, + copy.Y.c2.as_bigint().data, edwards_Fq::num_limbs, + copy.Y.c1.as_bigint().data, edwards_Fq::num_limbs, + copy.Y.c0.as_bigint().data, edwards_Fq::num_limbs); + } +} + +void edwards_G2::print_coordinates() const +{ + if (this->is_zero()) + { + printf("O\n"); + } + else + { + gmp_printf("(%Nd*z^2 + %Nd*z + %Nd : %Nd*z^2 + %Nd*z + %Nd : %Nd*z^2 + %Nd*z + %Nd)\n", + this->X.c2.as_bigint().data, edwards_Fq::num_limbs, + this->X.c1.as_bigint().data, edwards_Fq::num_limbs, + this->X.c0.as_bigint().data, edwards_Fq::num_limbs, + this->Y.c2.as_bigint().data, edwards_Fq::num_limbs, + this->Y.c1.as_bigint().data, edwards_Fq::num_limbs, + this->Y.c0.as_bigint().data, edwards_Fq::num_limbs, + this->Z.c2.as_bigint().data, edwards_Fq::num_limbs, + this->Z.c1.as_bigint().data, edwards_Fq::num_limbs, + this->Z.c0.as_bigint().data, edwards_Fq::num_limbs); + } +} + +void edwards_G2::to_affine_coordinates() +{ + if (this->is_zero()) + { + this->X = edwards_Fq3::zero(); + this->Y = edwards_Fq3::one(); + this->Z = edwards_Fq3::one(); + } + else + { + // go from inverted coordinates to projective coordinates + edwards_Fq3 tX = this->Y * this->Z; + edwards_Fq3 tY = this->X * this->Z; + edwards_Fq3 tZ = this->X * this->Y; + // go from projective coordinates to affine coordinates + edwards_Fq3 tZ_inv = tZ.inverse(); + this->X = tX * tZ_inv; + this->Y = tY * tZ_inv; + this->Z = edwards_Fq3::one(); + } +} + +void edwards_G2::to_special() +{ + if (this->Z.is_zero()) + { + return; + } + +#ifdef DEBUG + const edwards_G2 copy(*this); +#endif + + edwards_Fq3 Z_inv = this->Z.inverse(); + this->X = this->X * Z_inv; + this->Y = this->Y * Z_inv; + this->Z = edwards_Fq3::one(); + +#ifdef DEBUG + assert((*this) == copy); +#endif +} + +bool edwards_G2::is_special() const +{ + return (this->is_zero() || this->Z == edwards_Fq3::one()); +} + +bool edwards_G2::is_zero() const +{ + return (this->Y.is_zero() && this->Z.is_zero()); +} + +bool edwards_G2::operator==(const edwards_G2 &other) const +{ + if (this->is_zero()) + { + return other.is_zero(); + } + + if (other.is_zero()) + { + return false; + } + + /* now neither is O */ + + // X1/Z1 = X2/Z2 <=> X1*Z2 = X2*Z1 + if ((this->X * other.Z) != (other.X * this->Z)) + { + return false; + } + + // Y1/Z1 = Y2/Z2 <=> Y1*Z2 = Y2*Z1 + if ((this->Y * other.Z) != (other.Y * this->Z)) + { + return false; + } + + return true; +} + +bool edwards_G2::operator!=(const edwards_G2& other) const +{ + return !(operator==(other)); +} + +edwards_G2 edwards_G2::operator+(const edwards_G2 &other) const +{ + // handle special cases having to do with O + if (this->is_zero()) + { + return other; + } + + if (other.is_zero()) + { + return (*this); + } + + return this->add(other); +} + +edwards_G2 edwards_G2::operator-() const +{ + return edwards_G2(-(this->X), this->Y, this->Z); +} + + +edwards_G2 edwards_G2::operator-(const edwards_G2 &other) const +{ + return (*this) + (-other); +} + +edwards_G2 edwards_G2::add(const edwards_G2 &other) const +{ +#ifdef PROFILE_OP_COUNTS + this->add_cnt++; +#endif + // NOTE: does not handle O and pts of order 2,4 + // http://www.hyperelliptic.org/EFD/g1p/auto-twisted-inverted.html#addition-add-2008-bbjlp + + const edwards_Fq3 A = (this->Z) * (other.Z); // A = Z1*Z2 + const edwards_Fq3 B = edwards_G2::mul_by_d(A.squared()); // B = d*A^2 + const edwards_Fq3 C = (this->X) * (other.X); // C = X1*X2 + const edwards_Fq3 D = (this->Y) * (other.Y); // D = Y1*Y2 + const edwards_Fq3 E = C*D; // E = C*D + const edwards_Fq3 H = C - edwards_G2::mul_by_a(D); // H = C-a*D + const edwards_Fq3 I = (this->X+this->Y)*(other.X+other.Y)-C-D; // I = (X1+Y1)*(X2+Y2)-C-D + const edwards_Fq3 X3 = (E+B)*H; // X3 = (E+B)*H + const edwards_Fq3 Y3 = (E-B)*I; // Y3 = (E-B)*I + const edwards_Fq3 Z3 = A*H*I; // Z3 = A*H*I + + return edwards_G2(X3, Y3, Z3); +} + +edwards_G2 edwards_G2::mixed_add(const edwards_G2 &other) const +{ +#ifdef PROFILE_OP_COUNTS + this->add_cnt++; +#endif + // handle special cases having to do with O + if (this->is_zero()) + { + return other; + } + + if (other.is_zero()) + { + return *this; + } + +#ifdef DEBUG + assert(other.is_special()); +#endif + + // NOTE: does not handle O and pts of order 2,4 + // http://www.hyperelliptic.org/EFD/g1p/auto-edwards-inverted.html#addition-madd-2007-lb + + const edwards_Fq3 A = this->Z; // A = Z1*Z2 + const edwards_Fq3 B = edwards_G2::mul_by_d(A.squared()); // B = d*A^2 + const edwards_Fq3 C = (this->X) * (other.X); // C = X1*X2 + const edwards_Fq3 D = (this->Y) * (other.Y); // D = Y1*Y2 + const edwards_Fq3 E = C*D; // E = C*D + const edwards_Fq3 H = C - edwards_G2::mul_by_a(D); // H = C-a*D + const edwards_Fq3 I = (this->X+this->Y)*(other.X+other.Y)-C-D; // I = (X1+Y1)*(X2+Y2)-C-D + const edwards_Fq3 X3 = (E+B)*H; // X3 = (E+B)*H + const edwards_Fq3 Y3 = (E-B)*I; // Y3 = (E-B)*I + const edwards_Fq3 Z3 = A*H*I; // Z3 = A*H*I + + return edwards_G2(X3, Y3, Z3); +} + +edwards_G2 edwards_G2::dbl() const +{ +#ifdef PROFILE_OP_COUNTS + this->dbl_cnt++; +#endif + if (this->is_zero()) + { + return (*this); + } + else + { + // NOTE: does not handle O and pts of order 2,4 + // http://www.hyperelliptic.org/EFD/g1p/auto-twisted-inverted.html#doubling-dbl-2008-bbjlp + + const edwards_Fq3 A = (this->X).squared(); // A = X1^2 + const edwards_Fq3 B = (this->Y).squared(); // B = Y1^2 + const edwards_Fq3 U = edwards_G2::mul_by_a(B); // U = a*B + const edwards_Fq3 C = A+U; // C = A+U + const edwards_Fq3 D = A-U; // D = A-U + const edwards_Fq3 E = (this->X+this->Y).squared()-A-B; // E = (X1+Y1)^2-A-B + const edwards_Fq3 X3 = C*D; // X3 = C*D + const edwards_Fq3 dZZ = edwards_G2::mul_by_d(this->Z.squared()); + const edwards_Fq3 Y3 = E*(C-dZZ-dZZ); // Y3 = E*(C-2*d*Z1^2) + const edwards_Fq3 Z3 = D*E; // Z3 = D*E + + return edwards_G2(X3, Y3, Z3); + } +} + +edwards_G2 edwards_G2::mul_by_q() const +{ + return edwards_G2((this->X).Frobenius_map(1), + edwards_twist_mul_by_q_Y * (this->Y).Frobenius_map(1), + edwards_twist_mul_by_q_Z * (this->Z).Frobenius_map(1)); +} + +bool edwards_G2::is_well_formed() const +{ + /* Note that point at infinity is the only special case we must check as + inverted representation does no cover points (0, +-c) and (+-c, 0). */ + if (this->is_zero()) + { + return true; + } + else + { + /* + a x^2 + y^2 = 1 + d x^2 y^2 + + We are using inverted, so equation we need to check is actually + + a (z/x)^2 + (z/y)^2 = 1 + d z^4 / (x^2 * y^2) + z^2 (a y^2 + x^2 - dz^2) = x^2 y^2 + */ + edwards_Fq3 X2 = this->X.squared(); + edwards_Fq3 Y2 = this->Y.squared(); + edwards_Fq3 Z2 = this->Z.squared(); + edwards_Fq3 aY2 = edwards_G2::mul_by_a(Y2); + edwards_Fq3 dZ2 = edwards_G2::mul_by_d(Z2); + return (Z2 * (aY2 + X2 - dZ2) == X2 * Y2); + } +} + +edwards_G2 edwards_G2::zero() +{ + return G2_zero; +} + +edwards_G2 edwards_G2::one() +{ + return G2_one; +} + +edwards_G2 edwards_G2::random_element() +{ + return edwards_Fr::random_element().as_bigint() * G2_one; +} + +std::ostream& operator<<(std::ostream &out, const edwards_G2 &g) +{ + edwards_G2 copy(g); + copy.to_affine_coordinates(); +#ifdef NO_PT_COMPRESSION + out << copy.X << OUTPUT_SEPARATOR << copy.Y; +#else + /* storing LSB of Y */ + out << copy.X << OUTPUT_SEPARATOR << (copy.Y.c0.as_bigint().data[0] & 1); +#endif + return out; +} + +std::istream& operator>>(std::istream &in, edwards_G2 &g) +{ + edwards_Fq3 tX, tY; + +#ifdef NO_PT_COMPRESSION + in >> tX; + consume_OUTPUT_SEPARATOR(in); + in >> tY; +#else + /* + a x^2 + y^2 = 1 + d x^2 y^2 + y = sqrt((1-ax^2)/(1-dx^2)) + */ + unsigned char Y_lsb; + in >> tX; + consume_OUTPUT_SEPARATOR(in); + + in.read((char*)&Y_lsb, 1); + Y_lsb -= '0'; + + edwards_Fq3 tX2 = tX.squared(); + const edwards_Fq3 tY2 = + (edwards_Fq3::one() - edwards_G2::mul_by_a(tX2)) * + (edwards_Fq3::one() - edwards_G2::mul_by_d(tX2)).inverse(); + tY = tY2.sqrt(); + + if ((tY.c0.as_bigint().data[0] & 1) != Y_lsb) + { + tY = -tY; + } +#endif + + // using inverted coordinates + g.X = tY; + g.Y = tX; + g.Z = tX * tY; + +#ifdef USE_MIXED_ADDITION + g.to_special(); +#endif + + return in; +} + +template +void batch_to_special_all_non_zeros(std::vector &vec); +template<> +void batch_to_special_all_non_zeros(std::vector &vec) +{ + std::vector Z_vec; + Z_vec.reserve(vec.size()); + + for (auto &el: vec) + { + Z_vec.emplace_back(el.Z); + } + batch_invert(Z_vec); + + const edwards_Fq3 one = edwards_Fq3::one(); + + for (size_t i = 0; i < vec.size(); ++i) + { + vec[i].X = vec[i].X * Z_vec[i]; + vec[i].Y = vec[i].Y * Z_vec[i]; + vec[i].Z = one; + } +} + +} // libsnark diff --git a/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/edwards/edwards_g2.hpp b/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/edwards/edwards_g2.hpp new file mode 100644 index 0000000..bf35aef --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/edwards/edwards_g2.hpp @@ -0,0 +1,100 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef EDWARDS_G2_HPP_ +#define EDWARDS_G2_HPP_ +#include +#include +#include "algebra/curves/edwards/edwards_init.hpp" +#include "algebra/curves/curve_utils.hpp" + +namespace libsnark { + +class edwards_G2; +std::ostream& operator<<(std::ostream &, const edwards_G2&); +std::istream& operator>>(std::istream &, edwards_G2&); + +class edwards_G2 { +public: +#ifdef PROFILE_OP_COUNTS + static long long add_cnt; + static long long dbl_cnt; +#endif + static std::vector wnaf_window_table; + static std::vector fixed_base_exp_window_table; + + static edwards_G2 G2_zero; + static edwards_G2 G2_one; + + edwards_Fq3 X, Y, Z; + edwards_G2(); +private: + edwards_G2(const edwards_Fq3& X, const edwards_Fq3& Y, const edwards_Fq3& Z) : X(X), Y(Y), Z(Z) {}; +public: + static edwards_Fq3 mul_by_a(const edwards_Fq3 &elt); + static edwards_Fq3 mul_by_d(const edwards_Fq3 &elt); + typedef edwards_Fq base_field; + typedef edwards_Fq3 twist_field; + typedef edwards_Fr scalar_field; + + // using inverted coordinates + edwards_G2(const edwards_Fq3& X, const edwards_Fq3& Y) : X(Y), Y(X), Z(X*Y) {}; + + void print() const; + void print_coordinates() const; + + void to_affine_coordinates(); + void to_special(); + bool is_special() const; + + bool is_zero() const; + + bool operator==(const edwards_G2 &other) const; + bool operator!=(const edwards_G2 &other) const; + + edwards_G2 operator+(const edwards_G2 &other) const; + edwards_G2 operator-() const; + edwards_G2 operator-(const edwards_G2 &other) const; + + edwards_G2 add(const edwards_G2 &other) const; + edwards_G2 mixed_add(const edwards_G2 &other) const; + edwards_G2 dbl() const; + edwards_G2 mul_by_q() const; + + bool is_well_formed() const; + + static edwards_G2 zero(); + static edwards_G2 one(); + static edwards_G2 random_element(); + + static size_t size_in_bits() { return twist_field::size_in_bits() + 1; } + static bigint base_field_char() { return base_field::field_char(); } + static bigint order() { return scalar_field::field_char(); } + + friend std::ostream& operator<<(std::ostream &out, const edwards_G2 &g); + friend std::istream& operator>>(std::istream &in, edwards_G2 &g); +}; + +template +edwards_G2 operator*(const bigint &lhs, const edwards_G2 &rhs) +{ + return scalar_mul(rhs, lhs); +} + +template& modulus_p> +edwards_G2 operator*(const Fp_model &lhs, const edwards_G2 &rhs) +{ + return scalar_mul(rhs, lhs.as_bigint()); +} + +template +void batch_to_special_all_non_zeros(std::vector &vec); +template<> +void batch_to_special_all_non_zeros(std::vector &vec); + +} // libsnark +#endif // EDWARDS_G2_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/edwards/edwards_init.cpp b/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/edwards/edwards_init.cpp new file mode 100644 index 0000000..99538ac --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/edwards/edwards_init.cpp @@ -0,0 +1,270 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include "algebra/curves/edwards/edwards_init.hpp" +#include "algebra/curves/edwards/edwards_g1.hpp" +#include "algebra/curves/edwards/edwards_g2.hpp" + +namespace libsnark { + +bigint edwards_modulus_r; +bigint edwards_modulus_q; + +edwards_Fq edwards_coeff_a; +edwards_Fq edwards_coeff_d; +edwards_Fq3 edwards_twist; +edwards_Fq3 edwards_twist_coeff_a; +edwards_Fq3 edwards_twist_coeff_d; +edwards_Fq edwards_twist_mul_by_a_c0; +edwards_Fq edwards_twist_mul_by_a_c1; +edwards_Fq edwards_twist_mul_by_a_c2; +edwards_Fq edwards_twist_mul_by_d_c0; +edwards_Fq edwards_twist_mul_by_d_c1; +edwards_Fq edwards_twist_mul_by_d_c2; +edwards_Fq edwards_twist_mul_by_q_Y; +edwards_Fq edwards_twist_mul_by_q_Z; + +bigint edwards_ate_loop_count; +bigint<6*edwards_q_limbs> edwards_final_exponent; +bigint edwards_final_exponent_last_chunk_abs_of_w0; +bool edwards_final_exponent_last_chunk_is_w0_neg; +bigint edwards_final_exponent_last_chunk_w1; + +void init_edwards_params() +{ + typedef bigint bigint_r; + typedef bigint bigint_q; + + assert(sizeof(mp_limb_t) == 8 || sizeof(mp_limb_t) == 4); // Montgomery assumes this + + /* parameters for scalar field Fr */ + + edwards_modulus_r = bigint_r("1552511030102430251236801561344621993261920897571225601"); + assert(edwards_Fr::modulus_is_valid()); + if (sizeof(mp_limb_t) == 8) + { + edwards_Fr::Rsquared = bigint_r("621738487827897760168419760282818735947979812540885779"); + edwards_Fr::Rcubed = bigint_r("899968968216802386013510389846941393831065658679774050"); + edwards_Fr::inv = 0xdde553277fffffff; + } + if (sizeof(mp_limb_t) == 4) + { + edwards_Fr::Rsquared = bigint_r("621738487827897760168419760282818735947979812540885779"); + edwards_Fr::Rcubed = bigint_r("899968968216802386013510389846941393831065658679774050"); + edwards_Fr::inv = 0x7fffffff; + } + edwards_Fr::num_bits = 181; + edwards_Fr::euler = bigint_r("776255515051215125618400780672310996630960448785612800"); + edwards_Fr::s = 31; + edwards_Fr::t = bigint_r("722944284836962004768104088187507350585386575"); + edwards_Fr::t_minus_1_over_2 = bigint_r("361472142418481002384052044093753675292693287"); + edwards_Fr::multiplicative_generator = edwards_Fr("19"); + edwards_Fr::root_of_unity = edwards_Fr("695314865466598274460565335217615316274564719601897184"); + edwards_Fr::nqr = edwards_Fr("11"); + edwards_Fr::nqr_to_t = edwards_Fr("1326707053668679463752768729767248251415639579872144553"); + + /* parameters for base field Fq */ + + edwards_modulus_q = bigint_q("6210044120409721004947206240885978274523751269793792001"); + assert(edwards_Fq::modulus_is_valid()); + if (sizeof(mp_limb_t) == 8) + { + edwards_Fq::Rsquared = bigint_q("5943559676554581037560514598978484097352477055348195432"); + edwards_Fq::Rcubed = bigint_q("1081560488703514202058739223469726982199727506489234349"); + edwards_Fq::inv = 0x76eb690b7fffffff; + } + if (sizeof(mp_limb_t) == 4) + { + edwards_Fq::Rsquared = bigint_q("5943559676554581037560514598978484097352477055348195432"); + edwards_Fq::Rcubed = bigint_q("1081560488703514202058739223469726982199727506489234349"); + edwards_Fq::inv = 0x7fffffff; + } + edwards_Fq::num_bits = 183; + edwards_Fq::euler = bigint_q("3105022060204860502473603120442989137261875634896896000"); + edwards_Fq::s = 31; + edwards_Fq::t = bigint_q("2891777139347848019072416350658041552884388375"); + edwards_Fq::t_minus_1_over_2 = bigint_q("1445888569673924009536208175329020776442194187"); + edwards_Fq::multiplicative_generator = edwards_Fq("61"); + edwards_Fq::root_of_unity = edwards_Fq("4692813029219384139894873043933463717810008194158530536"); + edwards_Fq::nqr = edwards_Fq("23"); + edwards_Fq::nqr_to_t = edwards_Fq("2626736066325740702418554487368721595489070118548299138"); + + /* parameters for twist field Fq3 */ + + edwards_Fq3::euler = bigint<3*edwards_q_limbs>("119744082713971502962992613191067836698205043373978948903839934564152994858051284658545502971203325031831647424413111161318314144765646525057914792711854057586688000"); + edwards_Fq3::s = 31; + edwards_Fq3::t = bigint<3*edwards_q_limbs>("111520367408144756185815309352304634357062208814526860512643991563611659089151103662834971185031649686239331424621037357783237607000066456438894190557165125"); + edwards_Fq3::t_minus_1_over_2 = bigint<3*edwards_q_limbs>("55760183704072378092907654676152317178531104407263430256321995781805829544575551831417485592515824843119665712310518678891618803500033228219447095278582562"); + edwards_Fq3::non_residue = edwards_Fq("61"); + edwards_Fq3::nqr = edwards_Fq3(edwards_Fq("23"),edwards_Fq("0"),edwards_Fq("0")); + edwards_Fq3::nqr_to_t = edwards_Fq3(edwards_Fq("104810943629412208121981114244673004633270996333237516"),edwards_Fq("0"),edwards_Fq("0")); + edwards_Fq3::Frobenius_coeffs_c1[0] = edwards_Fq("1"); + edwards_Fq3::Frobenius_coeffs_c1[1] = edwards_Fq("1073752683758513276629212192812154536507607213288832061"); + edwards_Fq3::Frobenius_coeffs_c1[2] = edwards_Fq("5136291436651207728317994048073823738016144056504959939"); + edwards_Fq3::Frobenius_coeffs_c2[0] = edwards_Fq("1"); + edwards_Fq3::Frobenius_coeffs_c2[1] = edwards_Fq("5136291436651207728317994048073823738016144056504959939"); + edwards_Fq3::Frobenius_coeffs_c2[2] = edwards_Fq("1073752683758513276629212192812154536507607213288832061"); + + /* parameters for Fq6 */ + + edwards_Fq6::non_residue = edwards_Fq("61"); + edwards_Fq6::Frobenius_coeffs_c1[0] = edwards_Fq("1"); + edwards_Fq6::Frobenius_coeffs_c1[1] = edwards_Fq("1073752683758513276629212192812154536507607213288832062"); + edwards_Fq6::Frobenius_coeffs_c1[2] = edwards_Fq("1073752683758513276629212192812154536507607213288832061"); + edwards_Fq6::Frobenius_coeffs_c1[3] = edwards_Fq("6210044120409721004947206240885978274523751269793792000"); + edwards_Fq6::Frobenius_coeffs_c1[4] = edwards_Fq("5136291436651207728317994048073823738016144056504959939"); + edwards_Fq6::Frobenius_coeffs_c1[5] = edwards_Fq("5136291436651207728317994048073823738016144056504959940"); + edwards_Fq6::my_Fp2::non_residue = edwards_Fq3::non_residue; + + /* choice of Edwards curve and its twist */ + + edwards_coeff_a = edwards_Fq::one(); + edwards_coeff_d = edwards_Fq("600581931845324488256649384912508268813600056237543024"); + edwards_twist = edwards_Fq3(edwards_Fq::zero(), edwards_Fq::one(), edwards_Fq::zero()); + edwards_twist_coeff_a = edwards_coeff_a * edwards_twist; + edwards_twist_coeff_d = edwards_coeff_d * edwards_twist; + edwards_twist_mul_by_a_c0 = edwards_coeff_a * edwards_Fq3::non_residue; + edwards_twist_mul_by_a_c1 = edwards_coeff_a; + edwards_twist_mul_by_a_c2 = edwards_coeff_a; + edwards_twist_mul_by_d_c0 = edwards_coeff_d * edwards_Fq3::non_residue; + edwards_twist_mul_by_d_c1 = edwards_coeff_d; + edwards_twist_mul_by_d_c2 = edwards_coeff_d; + edwards_twist_mul_by_q_Y = edwards_Fq("1073752683758513276629212192812154536507607213288832062"); + edwards_twist_mul_by_q_Z = edwards_Fq("1073752683758513276629212192812154536507607213288832062"); + + /* choice of group G1 */ + + edwards_G1::G1_zero = edwards_G1(edwards_Fq::zero(), + edwards_Fq::one()); + edwards_G1::G1_one = edwards_G1(edwards_Fq("3713709671941291996998665608188072510389821008693530490"), + edwards_Fq("4869953702976555123067178261685365085639705297852816679")); + + edwards_G1::wnaf_window_table.resize(0); + edwards_G1::wnaf_window_table.push_back(9); + edwards_G1::wnaf_window_table.push_back(14); + edwards_G1::wnaf_window_table.push_back(24); + edwards_G1::wnaf_window_table.push_back(117); + + edwards_G1::fixed_base_exp_window_table.resize(0); + // window 1 is unbeaten in [-inf, 4.10] + edwards_G1::fixed_base_exp_window_table.push_back(1); + // window 2 is unbeaten in [4.10, 9.69] + edwards_G1::fixed_base_exp_window_table.push_back(4); + // window 3 is unbeaten in [9.69, 25.21] + edwards_G1::fixed_base_exp_window_table.push_back(10); + // window 4 is unbeaten in [25.21, 60.00] + edwards_G1::fixed_base_exp_window_table.push_back(25); + // window 5 is unbeaten in [60.00, 149.33] + edwards_G1::fixed_base_exp_window_table.push_back(60); + // window 6 is unbeaten in [149.33, 369.61] + edwards_G1::fixed_base_exp_window_table.push_back(149); + // window 7 is unbeaten in [369.61, 849.07] + edwards_G1::fixed_base_exp_window_table.push_back(370); + // window 8 is unbeaten in [849.07, 1764.94] + edwards_G1::fixed_base_exp_window_table.push_back(849); + // window 9 is unbeaten in [1764.94, 4429.59] + edwards_G1::fixed_base_exp_window_table.push_back(1765); + // window 10 is unbeaten in [4429.59, 13388.78] + edwards_G1::fixed_base_exp_window_table.push_back(4430); + // window 11 is unbeaten in [13388.78, 15368.00] + edwards_G1::fixed_base_exp_window_table.push_back(13389); + // window 12 is unbeaten in [15368.00, 74912.07] + edwards_G1::fixed_base_exp_window_table.push_back(15368); + // window 13 is unbeaten in [74912.07, 438107.20] + edwards_G1::fixed_base_exp_window_table.push_back(74912); + // window 14 is never the best + edwards_G1::fixed_base_exp_window_table.push_back(0); + // window 15 is unbeaten in [438107.20, 1045626.18] + edwards_G1::fixed_base_exp_window_table.push_back(438107); + // window 16 is never the best + edwards_G1::fixed_base_exp_window_table.push_back(0); + // window 17 is unbeaten in [1045626.18, 1577434.48] + edwards_G1::fixed_base_exp_window_table.push_back(1045626); + // window 18 is unbeaten in [1577434.48, 17350594.23] + edwards_G1::fixed_base_exp_window_table.push_back(1577434); + // window 19 is never the best + edwards_G1::fixed_base_exp_window_table.push_back(0); + // window 20 is never the best + edwards_G1::fixed_base_exp_window_table.push_back(0); + // window 21 is unbeaten in [17350594.23, inf] + edwards_G1::fixed_base_exp_window_table.push_back(17350594); + // window 22 is never the best + edwards_G1::fixed_base_exp_window_table.push_back(0); + + /* choice of group G2 */ + + edwards_G2::G2_zero = edwards_G2(edwards_Fq3::zero(), + edwards_Fq3::one()); + edwards_G2::G2_one = edwards_G2(edwards_Fq3(edwards_Fq("4531683359223370252210990718516622098304721701253228128"), + edwards_Fq("5339624155305731263217400504407647531329993548123477368"), + edwards_Fq("3964037981777308726208525982198654699800283729988686552")), + edwards_Fq3(edwards_Fq("364634864866983740775341816274081071386963546650700569"), + edwards_Fq("3264380230116139014996291397901297105159834497864380415"), + edwards_Fq("3504781284999684163274269077749440837914479176282903747"))); + + edwards_G2::wnaf_window_table.resize(0); + edwards_G2::wnaf_window_table.push_back(6); + edwards_G2::wnaf_window_table.push_back(12); + edwards_G2::wnaf_window_table.push_back(42); + edwards_G2::wnaf_window_table.push_back(97); + + edwards_G2::fixed_base_exp_window_table.resize(0); + // window 1 is unbeaten in [-inf, 4.74] + edwards_G2::fixed_base_exp_window_table.push_back(1); + // window 2 is unbeaten in [4.74, 10.67] + edwards_G2::fixed_base_exp_window_table.push_back(5); + // window 3 is unbeaten in [10.67, 25.53] + edwards_G2::fixed_base_exp_window_table.push_back(11); + // window 4 is unbeaten in [25.53, 60.67] + edwards_G2::fixed_base_exp_window_table.push_back(26); + // window 5 is unbeaten in [60.67, 145.77] + edwards_G2::fixed_base_exp_window_table.push_back(61); + // window 6 is unbeaten in [145.77, 356.76] + edwards_G2::fixed_base_exp_window_table.push_back(146); + // window 7 is unbeaten in [356.76, 823.08] + edwards_G2::fixed_base_exp_window_table.push_back(357); + // window 8 is unbeaten in [823.08, 1589.45] + edwards_G2::fixed_base_exp_window_table.push_back(823); + // window 9 is unbeaten in [1589.45, 4135.70] + edwards_G2::fixed_base_exp_window_table.push_back(1589); + // window 10 is unbeaten in [4135.70, 14297.74] + edwards_G2::fixed_base_exp_window_table.push_back(4136); + // window 11 is unbeaten in [14297.74, 16744.85] + edwards_G2::fixed_base_exp_window_table.push_back(14298); + // window 12 is unbeaten in [16744.85, 51768.98] + edwards_G2::fixed_base_exp_window_table.push_back(16745); + // window 13 is unbeaten in [51768.98, 99811.01] + edwards_G2::fixed_base_exp_window_table.push_back(51769); + // window 14 is unbeaten in [99811.01, 193306.72] + edwards_G2::fixed_base_exp_window_table.push_back(99811); + // window 15 is unbeaten in [193306.72, 907184.68] + edwards_G2::fixed_base_exp_window_table.push_back(193307); + // window 16 is never the best + edwards_G2::fixed_base_exp_window_table.push_back(0); + // window 17 is unbeaten in [907184.68, 1389682.59] + edwards_G2::fixed_base_exp_window_table.push_back(907185); + // window 18 is unbeaten in [1389682.59, 6752695.74] + edwards_G2::fixed_base_exp_window_table.push_back(1389683); + // window 19 is never the best + edwards_G2::fixed_base_exp_window_table.push_back(0); + // window 20 is unbeaten in [6752695.74, 193642894.51] + edwards_G2::fixed_base_exp_window_table.push_back(6752696); + // window 21 is unbeaten in [193642894.51, 226760202.29] + edwards_G2::fixed_base_exp_window_table.push_back(193642895); + // window 22 is unbeaten in [226760202.29, inf] + edwards_G2::fixed_base_exp_window_table.push_back(226760202); + + /* pairing parameters */ + + edwards_ate_loop_count = bigint_q("4492509698523932320491110403"); + edwards_final_exponent = bigint<6*edwards_q_limbs>("36943107177961694649618797346446870138748651578611748415128207429491593976636391130175425245705674550269561361208979548749447898941828686017765730419416875539615941651269793928962468899856083169227457503942470721108165443528513330156264699608120624990672333642644221591552000"); + edwards_final_exponent_last_chunk_abs_of_w0 = bigint_q("17970038794095729281964441603"); + edwards_final_exponent_last_chunk_is_w0_neg = true; + edwards_final_exponent_last_chunk_w1 = bigint_q("4"); + +} +} // libsnark diff --git a/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/edwards/edwards_init.hpp b/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/edwards/edwards_init.hpp new file mode 100644 index 0000000..3ada55b --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/edwards/edwards_init.hpp @@ -0,0 +1,61 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef EDWARDS_INIT_HPP_ +#define EDWARDS_INIT_HPP_ +#include "algebra/curves/public_params.hpp" +#include "algebra/fields/fp.hpp" +#include "algebra/fields/fp3.hpp" +#include "algebra/fields/fp6_2over3.hpp" + +namespace libsnark { + +const mp_size_t edwards_r_bitcount = 181; +const mp_size_t edwards_q_bitcount = 183; + +const mp_size_t edwards_r_limbs = (edwards_r_bitcount+GMP_NUMB_BITS-1)/GMP_NUMB_BITS; +const mp_size_t edwards_q_limbs = (edwards_q_bitcount+GMP_NUMB_BITS-1)/GMP_NUMB_BITS; + +extern bigint edwards_modulus_r; +extern bigint edwards_modulus_q; + +typedef Fp_model edwards_Fr; +typedef Fp_model edwards_Fq; +typedef Fp3_model edwards_Fq3; +typedef Fp6_2over3_model edwards_Fq6; +typedef edwards_Fq6 edwards_GT; + +// parameters for Edwards curve E_{1,d}(F_q) +extern edwards_Fq edwards_coeff_a; +extern edwards_Fq edwards_coeff_d; +// parameters for twisted Edwards curve E_{a',d'}(F_q^3) +extern edwards_Fq3 edwards_twist; +extern edwards_Fq3 edwards_twist_coeff_a; +extern edwards_Fq3 edwards_twist_coeff_d; +extern edwards_Fq edwards_twist_mul_by_a_c0; +extern edwards_Fq edwards_twist_mul_by_a_c1; +extern edwards_Fq edwards_twist_mul_by_a_c2; +extern edwards_Fq edwards_twist_mul_by_d_c0; +extern edwards_Fq edwards_twist_mul_by_d_c1; +extern edwards_Fq edwards_twist_mul_by_d_c2; +extern edwards_Fq edwards_twist_mul_by_q_Y; +extern edwards_Fq edwards_twist_mul_by_q_Z; + +// parameters for pairing +extern bigint edwards_ate_loop_count; +extern bigint<6*edwards_q_limbs> edwards_final_exponent; +extern bigint edwards_final_exponent_last_chunk_abs_of_w0; +extern bool edwards_final_exponent_last_chunk_is_w0_neg; +extern bigint edwards_final_exponent_last_chunk_w1; + +void init_edwards_params(); + +class edwards_G1; +class edwards_G2; + +} // libsnark +#endif // EDWARDS_INIT_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/edwards/edwards_pairing.cpp b/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/edwards/edwards_pairing.cpp new file mode 100644 index 0000000..22fab01 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/edwards/edwards_pairing.cpp @@ -0,0 +1,775 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include "algebra/curves/edwards/edwards_pairing.hpp" +#include "algebra/curves/edwards/edwards_init.hpp" +#include +#include "algebra/curves/edwards/edwards_g1.hpp" +#include "algebra/curves/edwards/edwards_g2.hpp" +#include "common/profiling.hpp" + +namespace libsnark { + +bool edwards_Fq_conic_coefficients::operator==(const edwards_Fq_conic_coefficients &other) const +{ + return (this->c_ZZ == other.c_ZZ && + this->c_XY == other.c_XY && + this->c_XZ == other.c_XZ); +} + +std::ostream& operator<<(std::ostream &out, const edwards_Fq_conic_coefficients &cc) +{ + out << cc.c_ZZ << OUTPUT_SEPARATOR << cc.c_XY << OUTPUT_SEPARATOR << cc.c_XZ; + return out; +} + +std::istream& operator>>(std::istream &in, edwards_Fq_conic_coefficients &cc) +{ + in >> cc.c_ZZ; + consume_OUTPUT_SEPARATOR(in); + in >> cc.c_XY; + consume_OUTPUT_SEPARATOR(in); + in >> cc.c_XZ; + return in; +} + +std::ostream& operator<<(std::ostream& out, const edwards_tate_G1_precomp &prec_P) +{ + out << prec_P.size() << "\n"; + for (const edwards_Fq_conic_coefficients &cc : prec_P) + { + out << cc << OUTPUT_NEWLINE; + } + + return out; +} + +std::istream& operator>>(std::istream& in, edwards_tate_G1_precomp &prec_P) +{ + prec_P.clear(); + + size_t s; + in >> s; + + consume_newline(in); + prec_P.reserve(s); + + for (size_t i = 0; i < s; ++i) + { + edwards_Fq_conic_coefficients cc; + in >> cc; + consume_OUTPUT_NEWLINE(in); + prec_P.emplace_back(cc); + } + + return in; +} + +bool edwards_tate_G2_precomp::operator==(const edwards_tate_G2_precomp &other) const +{ + return (this->y0 == other.y0 && + this->eta == other.eta); +} + +std::ostream& operator<<(std::ostream &out, const edwards_tate_G2_precomp &prec_Q) +{ + out << prec_Q.y0 << OUTPUT_SEPARATOR << prec_Q.eta; + return out; +} + +std::istream& operator>>(std::istream &in, edwards_tate_G2_precomp &prec_Q) +{ + in >> prec_Q.y0; + consume_OUTPUT_SEPARATOR(in); + in >> prec_Q.eta; + return in; +} + +bool edwards_Fq3_conic_coefficients::operator==(const edwards_Fq3_conic_coefficients &other) const +{ + return (this->c_ZZ == other.c_ZZ && + this->c_XY == other.c_XY && + this->c_XZ == other.c_XZ); +} + +std::ostream& operator<<(std::ostream &out, const edwards_Fq3_conic_coefficients &cc) +{ + out << cc.c_ZZ << OUTPUT_SEPARATOR << cc.c_XY << OUTPUT_SEPARATOR << cc.c_XZ; + return out; +} + +std::istream& operator>>(std::istream &in, edwards_Fq3_conic_coefficients &cc) +{ + in >> cc.c_ZZ; + consume_OUTPUT_SEPARATOR(in); + in >> cc.c_XY; + consume_OUTPUT_SEPARATOR(in); + in >> cc.c_XZ; + return in; +} + +std::ostream& operator<<(std::ostream& out, const edwards_ate_G2_precomp &prec_Q) +{ + out << prec_Q.size() << "\n"; + for (const edwards_Fq3_conic_coefficients &cc : prec_Q) + { + out << cc << OUTPUT_NEWLINE; + } + + return out; +} + +std::istream& operator>>(std::istream& in, edwards_ate_G2_precomp &prec_Q) +{ + prec_Q.clear(); + + size_t s; + in >> s; + + consume_newline(in); + + prec_Q.reserve(s); + + for (size_t i = 0; i < s; ++i) + { + edwards_Fq3_conic_coefficients cc; + in >> cc; + consume_OUTPUT_NEWLINE(in); + prec_Q.emplace_back(cc); + } + + return in; +} + +bool edwards_ate_G1_precomp::operator==(const edwards_ate_G1_precomp &other) const +{ + return (this->P_XY == other.P_XY && + this->P_XZ == other.P_XZ && + this->P_ZZplusYZ == other.P_ZZplusYZ); +} + +std::ostream& operator<<(std::ostream &out, const edwards_ate_G1_precomp &prec_P) +{ + out << prec_P.P_XY << OUTPUT_SEPARATOR << prec_P.P_XZ << OUTPUT_SEPARATOR << prec_P.P_ZZplusYZ; + + return out; +} + +std::istream& operator>>(std::istream &in, edwards_ate_G1_precomp &prec_P) +{ + in >> prec_P.P_XY >> prec_P.P_XZ >> prec_P.P_ZZplusYZ; + + return in; +} + +/* final exponentiations */ +edwards_Fq6 edwards_final_exponentiation_last_chunk(const edwards_Fq6 &elt, const edwards_Fq6 &elt_inv) +{ + enter_block("Call to edwards_final_exponentiation_last_chunk"); + const edwards_Fq6 elt_q = elt.Frobenius_map(1); + edwards_Fq6 w1_part = elt_q.cyclotomic_exp(edwards_final_exponent_last_chunk_w1); + edwards_Fq6 w0_part; + if (edwards_final_exponent_last_chunk_is_w0_neg) + { + w0_part = elt_inv.cyclotomic_exp(edwards_final_exponent_last_chunk_abs_of_w0); + } else { + w0_part = elt.cyclotomic_exp(edwards_final_exponent_last_chunk_abs_of_w0); + } + edwards_Fq6 result = w1_part * w0_part; + leave_block("Call to edwards_final_exponentiation_last_chunk"); + + return result; +} + +edwards_Fq6 edwards_final_exponentiation_first_chunk(const edwards_Fq6 &elt, const edwards_Fq6 &elt_inv) +{ + enter_block("Call to edwards_final_exponentiation_first_chunk"); + + /* (q^3-1)*(q+1) */ + + /* elt_q3 = elt^(q^3) */ + const edwards_Fq6 elt_q3 = elt.Frobenius_map(3); + /* elt_q3_over_elt = elt^(q^3-1) */ + const edwards_Fq6 elt_q3_over_elt = elt_q3 * elt_inv; + /* alpha = elt^((q^3-1) * q) */ + const edwards_Fq6 alpha = elt_q3_over_elt.Frobenius_map(1); + /* beta = elt^((q^3-1)*(q+1) */ + const edwards_Fq6 beta = alpha * elt_q3_over_elt; + leave_block("Call to edwards_final_exponentiation_first_chunk"); + return beta; +} + +edwards_GT edwards_final_exponentiation(const edwards_Fq6 &elt) +{ + enter_block("Call to edwards_final_exponentiation"); + const edwards_Fq6 elt_inv = elt.inverse(); + const edwards_Fq6 elt_to_first_chunk = edwards_final_exponentiation_first_chunk(elt, elt_inv); + const edwards_Fq6 elt_inv_to_first_chunk = edwards_final_exponentiation_first_chunk(elt_inv, elt); + edwards_GT result = edwards_final_exponentiation_last_chunk(elt_to_first_chunk, elt_inv_to_first_chunk); + leave_block("Call to edwards_final_exponentiation"); + + return result; +} + +edwards_tate_G2_precomp edwards_tate_precompute_G2(const edwards_G2& Q) +{ + enter_block("Call to edwards_tate_precompute_G2"); + edwards_G2 Qcopy = Q; + Qcopy.to_affine_coordinates(); + edwards_tate_G2_precomp result; + result.y0 = Qcopy.Y * Qcopy.Z.inverse(); // Y/Z + result.eta = (Qcopy.Z+Qcopy.Y) * edwards_Fq6::mul_by_non_residue(Qcopy.X).inverse(); // (Z+Y)/(nqr*X) + leave_block("Call to edwards_tate_precompute_G2"); + + return result; +} + +struct extended_edwards_G1_projective { + edwards_Fq X; + edwards_Fq Y; + edwards_Fq Z; + edwards_Fq T; + + void print() const + { + printf("extended edwards_G1 projective X/Y/Z/T:\n"); + X.print(); + Y.print(); + Z.print(); + T.print(); + } + + void test_invariant() const + { + assert(T*Z == X*Y); + } +}; + +void doubling_step_for_miller_loop(extended_edwards_G1_projective ¤t, + edwards_Fq_conic_coefficients &cc) +{ + const edwards_Fq &X = current.X, &Y = current.Y, &Z = current.Z, &T = current.T; + const edwards_Fq A = X.squared(); // A = X1^2 + const edwards_Fq B = Y.squared(); // B = Y1^2 + const edwards_Fq C = Z.squared(); // C = Z1^2 + const edwards_Fq D = (X+Y).squared(); // D = (X1+Y1)^2 + const edwards_Fq E = (Y+Z).squared(); // E = (Y1+Z1)^2 + const edwards_Fq F = D-(A+B); // F = D-(A+B) + const edwards_Fq G = E-(B+C); // G = E-(B+C) + const edwards_Fq &H = A; // H = A (edwards_a=1) + const edwards_Fq I = H+B; // I = H+B + const edwards_Fq J = C-I; // J = C-I + const edwards_Fq K = J+C; // K = J+C + + cc.c_ZZ = Y*(T-X); // c_ZZ = 2*Y1*(T1-X1) + cc.c_ZZ = cc.c_ZZ + cc.c_ZZ; + + cc.c_XY = J+J+G; // c_XY = 2*J+G + cc.c_XZ = X*T-B; // c_XZ = 2*(X1*T1-B) (edwards_a=1) + cc.c_XZ = cc.c_XZ + cc.c_XZ; + + current.X = F*K; // X3 = F*K + current.Y = I*(B-H); // Y3 = I*(B-H) + current.Z = I*K; // Z3 = I*K + current.T = F*(B-H); // T3 = F*(B-H) + +#ifdef DEBUG + current.test_invariant(); +#endif +} + +void full_addition_step_for_miller_loop(const extended_edwards_G1_projective &base, + extended_edwards_G1_projective ¤t, + edwards_Fq_conic_coefficients &cc) +{ + const edwards_Fq &X1 = current.X, &Y1 = current.Y, &Z1 = current.Z, &T1 = current.T; + const edwards_Fq &X2 = base.X, &Y2 = base.Y, &Z2 = base.Z, &T2 = base.T; + + const edwards_Fq A = X1*X2; // A = X1*X2 + const edwards_Fq B = Y1*Y2; // B = Y1*Y2 + const edwards_Fq C = Z1*T2; // C = Z1*T2 + const edwards_Fq D = T1*Z2; // D = T1*Z2 + const edwards_Fq E = D+C; // E = D+C + const edwards_Fq F = (X1-Y1)*(X2+Y2)+B-A; // F = (X1-Y1)*(X2+Y2)+B-A + const edwards_Fq G = B + A; // G = B + A (edwards_a=1) + const edwards_Fq H = D-C; // H = D-C + const edwards_Fq I = T1*T2; // I = T1*T2 + + cc.c_ZZ = (T1-X1)*(T2+X2)-I+A; // c_ZZ = (T1-X1)*(T2+X2)-I+A + cc.c_XY = X1*Z2-X2*Z1+F; // c_XY = X1*Z2-X2*Z1+F + cc.c_XZ = (Y1-T1)*(Y2+T2)-B+I-H; // c_XZ = (Y1-T1)*(Y2+T2)-B+I-H + current.X = E*F; // X3 = E*F + current.Y = G*H; // Y3 = G*H + current.Z = F*G; // Z3 = F*G + current.T = E*H; // T3 = E*H + +#ifdef DEBUG + current.test_invariant(); +#endif +} + +void mixed_addition_step_for_miller_loop(const extended_edwards_G1_projective &base, + extended_edwards_G1_projective ¤t, + edwards_Fq_conic_coefficients &cc) +{ + const edwards_Fq &X1 = current.X, &Y1 = current.Y, &Z1 = current.Z, &T1 = current.T; + const edwards_Fq &X2 = base.X, &Y2 = base.Y, &T2 = base.T; + + const edwards_Fq A = X1*X2; // A = X1*X2 + const edwards_Fq B = Y1*Y2; // B = Y1*Y2 + const edwards_Fq C = Z1*T2; // C = Z1*T2 + const edwards_Fq D = T1; // D = T1*Z2 + const edwards_Fq E = D+C; // E = D+C + const edwards_Fq F = (X1-Y1)*(X2+Y2)+B-A; // F = (X1-Y1)*(X2+Y2)+B-A + const edwards_Fq G = B + A; // G = B + A (edwards_a=1) + const edwards_Fq H = D-C; // H = D-C + const edwards_Fq I = T1*T2; // I = T1*T2 + + cc.c_ZZ = (T1-X1)*(T2+X2)-I+A; // c_ZZ = (T1-X1)*(T2+X2)-I+A + cc.c_XY = X1-X2*Z1+F; // c_XY = X1*Z2-X2*Z1+F + cc.c_XZ = (Y1-T1)*(Y2+T2)-B+I-H; // c_XZ = (Y1-T1)*(Y2+T2)-B+I-H + current.X = E*F; // X3 = E*F + current.Y = G*H; // Y3 = G*H + current.Z = F*G; // Z3 = F*G + current.T = E*H; // T3 = E*H + +#ifdef DEBUG + current.test_invariant(); +#endif +} + +edwards_tate_G1_precomp edwards_tate_precompute_G1(const edwards_G1& P) +{ + enter_block("Call to edwards_tate_precompute_G1"); + edwards_tate_G1_precomp result; + + edwards_G1 Pcopy = P; + Pcopy.to_affine_coordinates(); + + extended_edwards_G1_projective P_ext; + P_ext.X = Pcopy.X; + P_ext.Y = Pcopy.Y; + P_ext.Z = Pcopy.Z; + P_ext.T = Pcopy.X*Pcopy.Y; + + extended_edwards_G1_projective R = P_ext; + + bool found_one = false; + for (long i = edwards_modulus_r.max_bits(); i >= 0; --i) + { + const bool bit = edwards_modulus_r.test_bit(i); + if (!found_one) + { + /* this skips the MSB itself */ + found_one |= bit; + continue; + } + + /* code below gets executed for all bits (EXCEPT the MSB itself) of + edwards_modulus_r (skipping leading zeros) in MSB to LSB + order */ + edwards_Fq_conic_coefficients cc; + doubling_step_for_miller_loop(R, cc); + result.push_back(cc); + + if (bit) + { + mixed_addition_step_for_miller_loop(P_ext, R, cc); + result.push_back(cc); + } + } + + leave_block("Call to edwards_tate_precompute_G1"); + return result; +} + +edwards_Fq6 edwards_tate_miller_loop(const edwards_tate_G1_precomp &prec_P, + const edwards_tate_G2_precomp &prec_Q) +{ + enter_block("Call to edwards_tate_miller_loop"); + + edwards_Fq6 f = edwards_Fq6::one(); + + bool found_one = false; + size_t idx = 0; + for (long i = edwards_modulus_r.max_bits()-1; i >= 0; --i) + { + const bool bit = edwards_modulus_r.test_bit(i); + if (!found_one) + { + /* this skips the MSB itself */ + found_one |= bit; + continue; + } + + /* code below gets executed for all bits (EXCEPT the MSB itself) of + edwards_modulus_r (skipping leading zeros) in MSB to LSB + order */ + edwards_Fq_conic_coefficients cc = prec_P[idx++]; + edwards_Fq6 g_RR_at_Q = edwards_Fq6(edwards_Fq3(cc.c_XZ, edwards_Fq(0l), edwards_Fq(0l)) + cc.c_XY * prec_Q.y0, + cc.c_ZZ * prec_Q.eta); + f = f.squared() * g_RR_at_Q; + if (bit) + { + cc = prec_P[idx++]; + + edwards_Fq6 g_RP_at_Q = edwards_Fq6(edwards_Fq3(cc.c_XZ, edwards_Fq(0l), edwards_Fq(0l)) + cc.c_XY * prec_Q.y0, + cc.c_ZZ * prec_Q.eta); + f = f * g_RP_at_Q; + } + } + leave_block("Call to edwards_tate_miller_loop"); + + return f; +} + +edwards_Fq6 edwards_tate_pairing(const edwards_G1& P, const edwards_G2 &Q) +{ + enter_block("Call to edwards_tate_pairing"); + edwards_tate_G1_precomp prec_P = edwards_tate_precompute_G1(P); + edwards_tate_G2_precomp prec_Q = edwards_tate_precompute_G2(Q); + edwards_Fq6 result = edwards_tate_miller_loop(prec_P, prec_Q); + leave_block("Call to edwards_tate_pairing"); + return result; +} + +edwards_GT edwards_tate_reduced_pairing(const edwards_G1 &P, const edwards_G2 &Q) +{ + enter_block("Call to edwards_tate_reduced_pairing"); + const edwards_Fq6 f = edwards_tate_pairing(P, Q); + const edwards_GT result = edwards_final_exponentiation(f); + leave_block("Call to edwards_tate_reduce_pairing"); + return result; +} + +struct extended_edwards_G2_projective { + edwards_Fq3 X; + edwards_Fq3 Y; + edwards_Fq3 Z; + edwards_Fq3 T; + + void print() const + { + printf("extended edwards_G2 projective X/Y/Z/T:\n"); + X.print(); + Y.print(); + Z.print(); + T.print(); + } + + void test_invariant() const + { + assert(T*Z == X*Y); + } +}; + +void doubling_step_for_flipped_miller_loop(extended_edwards_G2_projective ¤t, + edwards_Fq3_conic_coefficients &cc) +{ + const edwards_Fq3 &X = current.X, &Y = current.Y, &Z = current.Z, &T = current.T; + const edwards_Fq3 A = X.squared(); // A = X1^2 + const edwards_Fq3 B = Y.squared(); // B = Y1^2 + const edwards_Fq3 C = Z.squared(); // C = Z1^2 + const edwards_Fq3 D = (X+Y).squared(); // D = (X1+Y1)^2 + const edwards_Fq3 E = (Y+Z).squared(); // E = (Y1+Z1)^2 + const edwards_Fq3 F = D-(A+B); // F = D-(A+B) + const edwards_Fq3 G = E-(B+C); // G = E-(B+C) + const edwards_Fq3 H = edwards_G2::mul_by_a(A); // edwards_param_twist_coeff_a is 1 * X for us + // H = twisted_a * A + const edwards_Fq3 I = H+B; // I = H+B + const edwards_Fq3 J = C-I; // J = C-I + const edwards_Fq3 K = J+C; // K = J+C + + cc.c_ZZ = Y*(T-X); // c_ZZ = 2*Y1*(T1-X1) + cc.c_ZZ = cc.c_ZZ + cc.c_ZZ; + + // c_XY = 2*(C-edwards_a * A * delta_3-B)+G (edwards_a = 1 for us) + cc.c_XY = C - edwards_G2::mul_by_a(A) - B; // edwards_param_twist_coeff_a is 1 * X for us + cc.c_XY = cc.c_XY + cc.c_XY + G; + + // c_XZ = 2*(edwards_a*X1*T1*delta_3-B) (edwards_a = 1 for us) + cc.c_XZ = edwards_G2::mul_by_a(X * T) - B; // edwards_param_twist_coeff_a is 1 * X for us + cc.c_XZ = cc.c_XZ + cc.c_XZ; + + current.X = F*K; // X3 = F*K + current.Y = I*(B-H); // Y3 = I*(B-H) + current.Z = I*K; // Z3 = I*K + current.T = F*(B-H); // T3 = F*(B-H) +#ifdef DEBUG + current.test_invariant(); +#endif +} + +void full_addition_step_for_flipped_miller_loop(const extended_edwards_G2_projective &base, + extended_edwards_G2_projective ¤t, + edwards_Fq3_conic_coefficients &cc) +{ + const edwards_Fq3 &X1 = current.X, &Y1 = current.Y, &Z1 = current.Z, &T1 = current.T; + const edwards_Fq3 &X2 = base.X, &Y2 = base.Y, &Z2 = base.Z, &T2 = base.T; + + const edwards_Fq3 A = X1*X2; // A = X1*X2 + const edwards_Fq3 B = Y1*Y2; // B = Y1*Y2 + const edwards_Fq3 C = Z1*T2; // C = Z1*T2 + const edwards_Fq3 D = T1*Z2; // D = T1*Z2 + const edwards_Fq3 E = D+C; // E = D+C + const edwards_Fq3 F = (X1-Y1)*(X2+Y2)+B-A; // F = (X1-Y1)*(X2+Y2)+B-A + // G = B + twisted_edwards_a * A + const edwards_Fq3 G = B + edwards_G2::mul_by_a(A); // edwards_param_twist_coeff_a is 1*X for us + const edwards_Fq3 H = D-C; // H = D-C + const edwards_Fq3 I = T1*T2; // I = T1*T2 + + // c_ZZ = delta_3* ((T1-X1)*(T2+X2)-I+A) + cc.c_ZZ = edwards_G2::mul_by_a((T1-X1)*(T2+X2)-I+A); // edwards_param_twist_coeff_a is 1*X for us + + cc.c_XY = X1*Z2-X2*Z1+F; // c_XY = X1*Z2-X2*Z1+F + cc.c_XZ = (Y1-T1)*(Y2+T2)-B+I-H; // c_XZ = (Y1-T1)*(Y2+T2)-B+I-H + current.X = E*F; // X3 = E*F + current.Y = G*H; // Y3 = G*H + current.Z = F*G; // Z3 = F*G + current.T = E*H; // T3 = E*H + +#ifdef DEBUG + current.test_invariant(); +#endif +} + +void mixed_addition_step_for_flipped_miller_loop(const extended_edwards_G2_projective &base, + extended_edwards_G2_projective ¤t, + edwards_Fq3_conic_coefficients &cc) +{ + const edwards_Fq3 &X1 = current.X, &Y1 = current.Y, &Z1 = current.Z, &T1 = current.T; + const edwards_Fq3 &X2 = base.X, &Y2 = base.Y, &T2 = base.T; + + const edwards_Fq3 A = X1*X2; // A = X1*X2 + const edwards_Fq3 B = Y1*Y2; // B = Y1*Y2 + const edwards_Fq3 C = Z1*T2; // C = Z1*T2 + const edwards_Fq3 E = T1+C; // E = T1+C + const edwards_Fq3 F = (X1-Y1)*(X2+Y2)+B-A; // F = (X1-Y1)*(X2+Y2)+B-A + // G = B + twisted_edwards_a * A + const edwards_Fq3 G = B + edwards_G2::mul_by_a(A); // edwards_param_twist_coeff_a is 1*X for us + const edwards_Fq3 H = T1-C; // H = T1-C + const edwards_Fq3 I = T1*T2; // I = T1*T2 + + // c_ZZ = delta_3* ((T1-X1)*(T2+X2)-I+A) + cc.c_ZZ = edwards_G2::mul_by_a((T1-X1)*(T2+X2)-I+A); // edwards_param_twist_coeff_a is 1*X for us + + cc.c_XY = X1-X2*Z1+F; // c_XY = X1*Z2-X2*Z1+F + cc.c_XZ = (Y1-T1)*(Y2+T2)-B+I-H; // c_XZ = (Y1-T1)*(Y2+T2)-B+I-H + current.X = E*F; // X3 = E*F + current.Y = G*H; // Y3 = G*H + current.Z = F*G; // Z3 = F*G + current.T = E*H; // T3 = E*H + +#ifdef DEBUG + current.test_invariant(); +#endif +} + +edwards_ate_G1_precomp edwards_ate_precompute_G1(const edwards_G1& P) +{ + enter_block("Call to edwards_ate_precompute_G1"); + edwards_G1 Pcopy = P; + Pcopy.to_affine_coordinates(); + edwards_ate_G1_precomp result; + result.P_XY = Pcopy.X*Pcopy.Y; + result.P_XZ = Pcopy.X; // P.X * P.Z but P.Z = 1 + result.P_ZZplusYZ = (edwards_Fq::one() + Pcopy.Y); // (P.Z + P.Y) * P.Z but P.Z = 1 + leave_block("Call to edwards_ate_precompute_G1"); + return result; +} + +edwards_ate_G2_precomp edwards_ate_precompute_G2(const edwards_G2& Q) +{ + enter_block("Call to edwards_ate_precompute_G2"); + const bigint &loop_count = edwards_ate_loop_count; + edwards_ate_G2_precomp result; + + edwards_G2 Qcopy(Q); + Qcopy.to_affine_coordinates(); + + extended_edwards_G2_projective Q_ext; + Q_ext.X = Qcopy.X; + Q_ext.Y = Qcopy.Y; + Q_ext.Z = Qcopy.Z; + Q_ext.T = Qcopy.X*Qcopy.Y; + + extended_edwards_G2_projective R = Q_ext; + + bool found_one = false; + for (long i = loop_count.max_bits()-1; i >= 0; --i) + { + const bool bit = loop_count.test_bit(i); + if (!found_one) + { + /* this skips the MSB itself */ + found_one |= bit; + continue; + } + + edwards_Fq3_conic_coefficients cc; + doubling_step_for_flipped_miller_loop(R, cc); + result.push_back(cc); + if (bit) + { + mixed_addition_step_for_flipped_miller_loop(Q_ext, R, cc); + result.push_back(cc); + } + } + + leave_block("Call to edwards_ate_precompute_G2"); + return result; +} + +edwards_Fq6 edwards_ate_miller_loop(const edwards_ate_G1_precomp &prec_P, + const edwards_ate_G2_precomp &prec_Q) +{ + enter_block("Call to edwards_ate_miller_loop"); + const bigint &loop_count = edwards_ate_loop_count; + + edwards_Fq6 f = edwards_Fq6::one(); + + bool found_one = false; + size_t idx = 0; + for (long i = loop_count.max_bits()-1; i >= 0; --i) + { + const bool bit = loop_count.test_bit(i); + if (!found_one) + { + /* this skips the MSB itself */ + found_one |= bit; + continue; + } + + /* code below gets executed for all bits (EXCEPT the MSB itself) of + edwards_param_p (skipping leading zeros) in MSB to LSB + order */ + edwards_Fq3_conic_coefficients cc = prec_Q[idx++]; + + edwards_Fq6 g_RR_at_P = edwards_Fq6(prec_P.P_XY * cc.c_XY + prec_P.P_XZ * cc.c_XZ, + prec_P.P_ZZplusYZ * cc.c_ZZ); + f = f.squared() * g_RR_at_P; + if (bit) + { + cc = prec_Q[idx++]; + edwards_Fq6 g_RQ_at_P = edwards_Fq6(prec_P.P_ZZplusYZ * cc.c_ZZ, + prec_P.P_XY * cc.c_XY + prec_P.P_XZ * cc.c_XZ); + f = f * g_RQ_at_P; + } + } + leave_block("Call to edwards_ate_miller_loop"); + + return f; +} + +edwards_Fq6 edwards_ate_double_miller_loop(const edwards_ate_G1_precomp &prec_P1, + const edwards_ate_G2_precomp &prec_Q1, + const edwards_ate_G1_precomp &prec_P2, + const edwards_ate_G2_precomp &prec_Q2) +{ + enter_block("Call to edwards_ate_double_miller_loop"); + const bigint &loop_count = edwards_ate_loop_count; + + edwards_Fq6 f = edwards_Fq6::one(); + + bool found_one = false; + size_t idx = 0; + for (long i = loop_count.max_bits()-1; i >= 0; --i) + { + const bool bit = loop_count.test_bit(i); + if (!found_one) + { + /* this skips the MSB itself */ + found_one |= bit; + continue; + } + + /* code below gets executed for all bits (EXCEPT the MSB itself) of + edwards_param_p (skipping leading zeros) in MSB to LSB + order */ + edwards_Fq3_conic_coefficients cc1 = prec_Q1[idx]; + edwards_Fq3_conic_coefficients cc2 = prec_Q2[idx]; + ++idx; + + edwards_Fq6 g_RR_at_P1 = edwards_Fq6(prec_P1.P_XY * cc1.c_XY + prec_P1.P_XZ * cc1.c_XZ, + prec_P1.P_ZZplusYZ * cc1.c_ZZ); + + edwards_Fq6 g_RR_at_P2 = edwards_Fq6(prec_P2.P_XY * cc2.c_XY + prec_P2.P_XZ * cc2.c_XZ, + prec_P2.P_ZZplusYZ * cc2.c_ZZ); + f = f.squared() * g_RR_at_P1 * g_RR_at_P2; + + if (bit) + { + cc1 = prec_Q1[idx]; + cc2 = prec_Q2[idx]; + ++idx; + edwards_Fq6 g_RQ_at_P1 = edwards_Fq6(prec_P1.P_ZZplusYZ * cc1.c_ZZ, + prec_P1.P_XY * cc1.c_XY + prec_P1.P_XZ * cc1.c_XZ); + edwards_Fq6 g_RQ_at_P2 = edwards_Fq6(prec_P2.P_ZZplusYZ * cc2.c_ZZ, + prec_P2.P_XY * cc2.c_XY + prec_P2.P_XZ * cc2.c_XZ); + f = f * g_RQ_at_P1 * g_RQ_at_P2; + } + } + leave_block("Call to edwards_ate_double_miller_loop"); + + return f; +} + +edwards_Fq6 edwards_ate_pairing(const edwards_G1& P, const edwards_G2 &Q) +{ + enter_block("Call to edwards_ate_pairing"); + edwards_ate_G1_precomp prec_P = edwards_ate_precompute_G1(P); + edwards_ate_G2_precomp prec_Q = edwards_ate_precompute_G2(Q); + edwards_Fq6 result = edwards_ate_miller_loop(prec_P, prec_Q); + leave_block("Call to edwards_ate_pairing"); + return result; +} + +edwards_GT edwards_ate_reduced_pairing(const edwards_G1 &P, const edwards_G2 &Q) +{ + enter_block("Call to edwards_ate_reduced_pairing"); + const edwards_Fq6 f = edwards_ate_pairing(P, Q); + const edwards_GT result = edwards_final_exponentiation(f); + leave_block("Call to edwards_ate_reduced_pairing"); + return result; +} + +edwards_G1_precomp edwards_precompute_G1(const edwards_G1& P) +{ + return edwards_ate_precompute_G1(P); +} + +edwards_G2_precomp edwards_precompute_G2(const edwards_G2& Q) +{ + return edwards_ate_precompute_G2(Q); +} + +edwards_Fq6 edwards_miller_loop(const edwards_G1_precomp &prec_P, + const edwards_G2_precomp &prec_Q) +{ + return edwards_ate_miller_loop(prec_P, prec_Q); +} + +edwards_Fq6 edwards_double_miller_loop(const edwards_G1_precomp &prec_P1, + const edwards_G2_precomp &prec_Q1, + const edwards_G1_precomp &prec_P2, + const edwards_G2_precomp &prec_Q2) +{ + return edwards_ate_double_miller_loop(prec_P1, prec_Q1, prec_P2, prec_Q2); +} + +edwards_Fq6 edwards_pairing(const edwards_G1& P, + const edwards_G2 &Q) +{ + return edwards_ate_pairing(P, Q); +} + +edwards_GT edwards_reduced_pairing(const edwards_G1 &P, + const edwards_G2 &Q) +{ + return edwards_ate_reduced_pairing(P, Q); +} +} // libsnark diff --git a/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/edwards/edwards_pairing.hpp b/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/edwards/edwards_pairing.hpp new file mode 100644 index 0000000..f838ae3 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/edwards/edwards_pairing.hpp @@ -0,0 +1,122 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef EDWARDS_PAIRING_HPP_ +#define EDWARDS_PAIRING_HPP_ +#include +#include "algebra/curves/edwards/edwards_init.hpp" + +namespace libsnark { + +/* final exponentiation */ + +edwards_Fq6 edwards_final_exponentiation_last_chunk(const edwards_Fq6 &elt, + const edwards_Fq6 &elt_inv); +edwards_Fq6 edwards_final_exponentiation_first_chunk(const edwards_Fq6 &elt, + const edwards_Fq6 &elt_inv); +edwards_GT edwards_final_exponentiation(const edwards_Fq6 &elt); + +/* Tate pairing */ + +struct edwards_Fq_conic_coefficients { + edwards_Fq c_ZZ; + edwards_Fq c_XY; + edwards_Fq c_XZ; + + bool operator==(const edwards_Fq_conic_coefficients &other) const; + friend std::ostream& operator<<(std::ostream &out, const edwards_Fq_conic_coefficients &cc); + friend std::istream& operator>>(std::istream &in, edwards_Fq_conic_coefficients &cc); +}; +typedef std::vector edwards_tate_G1_precomp; + +std::ostream& operator<<(std::ostream& out, const edwards_tate_G1_precomp &prec_P); +std::istream& operator>>(std::istream& in, edwards_tate_G1_precomp &prec_P); + +struct edwards_tate_G2_precomp { + edwards_Fq3 y0, eta; + + bool operator==(const edwards_tate_G2_precomp &other) const; + friend std::ostream& operator<<(std::ostream &out, const edwards_tate_G2_precomp &prec_Q); + friend std::istream& operator>>(std::istream &in, edwards_tate_G2_precomp &prec_Q); +}; + +edwards_tate_G1_precomp edwards_tate_precompute_G1(const edwards_G1& P); +edwards_tate_G2_precomp edwards_tate_precompute_G2(const edwards_G2& Q); + +edwards_Fq6 edwards_tate_miller_loop(const edwards_tate_G1_precomp &prec_P, + const edwards_tate_G2_precomp &prec_Q); + +edwards_Fq6 edwards_tate_pairing(const edwards_G1& P, + const edwards_G2 &Q); +edwards_GT edwards_tate_reduced_pairing(const edwards_G1 &P, + const edwards_G2 &Q); + +/* ate pairing */ + +struct edwards_Fq3_conic_coefficients { + edwards_Fq3 c_ZZ; + edwards_Fq3 c_XY; + edwards_Fq3 c_XZ; + + bool operator==(const edwards_Fq3_conic_coefficients &other) const; + friend std::ostream& operator<<(std::ostream &out, const edwards_Fq3_conic_coefficients &cc); + friend std::istream& operator>>(std::istream &in, edwards_Fq3_conic_coefficients &cc); +}; +typedef std::vector edwards_ate_G2_precomp; + +std::ostream& operator<<(std::ostream& out, const edwards_ate_G2_precomp &prec_Q); +std::istream& operator>>(std::istream& in, edwards_ate_G2_precomp &prec_Q); + +struct edwards_ate_G1_precomp { + edwards_Fq P_XY; + edwards_Fq P_XZ; + edwards_Fq P_ZZplusYZ; + + bool operator==(const edwards_ate_G1_precomp &other) const; + friend std::ostream& operator<<(std::ostream &out, const edwards_ate_G1_precomp &prec_P); + friend std::istream& operator>>(std::istream &in, edwards_ate_G1_precomp &prec_P); +}; + +edwards_ate_G1_precomp edwards_ate_precompute_G1(const edwards_G1& P); +edwards_ate_G2_precomp edwards_ate_precompute_G2(const edwards_G2& Q); + +edwards_Fq6 edwards_ate_miller_loop(const edwards_ate_G1_precomp &prec_P, + const edwards_ate_G2_precomp &prec_Q); +edwards_Fq6 edwards_ate_double_miller_loop(const edwards_ate_G1_precomp &prec_P1, + const edwards_ate_G2_precomp &prec_Q1, + const edwards_ate_G1_precomp &prec_P2, + const edwards_ate_G2_precomp &prec_Q2); + +edwards_Fq6 edwards_ate_pairing(const edwards_G1& P, + const edwards_G2 &Q); +edwards_GT edwards_ate_reduced_pairing(const edwards_G1 &P, + const edwards_G2 &Q); + +/* choice of pairing */ + +typedef edwards_ate_G1_precomp edwards_G1_precomp; +typedef edwards_ate_G2_precomp edwards_G2_precomp; + +edwards_G1_precomp edwards_precompute_G1(const edwards_G1& P); +edwards_G2_precomp edwards_precompute_G2(const edwards_G2& Q); + +edwards_Fq6 edwards_miller_loop(const edwards_G1_precomp &prec_P, + const edwards_G2_precomp &prec_Q); + +edwards_Fq6 edwards_double_miller_loop(const edwards_G1_precomp &prec_P1, + const edwards_G2_precomp &prec_Q1, + const edwards_G1_precomp &prec_P2, + const edwards_G2_precomp &prec_Q2); + +edwards_Fq6 edwards_pairing(const edwards_G1& P, + const edwards_G2 &Q); + +edwards_GT edwards_reduced_pairing(const edwards_G1 &P, + const edwards_G2 &Q); + +} // libsnark +#endif // EDWARDS_PAIRING_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/edwards/edwards_pp.cpp b/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/edwards/edwards_pp.cpp new file mode 100644 index 0000000..5af4010 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/edwards/edwards_pp.cpp @@ -0,0 +1,58 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include "algebra/curves/edwards/edwards_pp.hpp" + +namespace libsnark { + +void edwards_pp::init_public_params() +{ + init_edwards_params(); +} + +edwards_GT edwards_pp::final_exponentiation(const edwards_Fq6 &elt) +{ + return edwards_final_exponentiation(elt); +} + +edwards_G1_precomp edwards_pp::precompute_G1(const edwards_G1 &P) +{ + return edwards_precompute_G1(P); +} + +edwards_G2_precomp edwards_pp::precompute_G2(const edwards_G2 &Q) +{ + return edwards_precompute_G2(Q); +} + +edwards_Fq6 edwards_pp::miller_loop(const edwards_G1_precomp &prec_P, + const edwards_G2_precomp &prec_Q) +{ + return edwards_miller_loop(prec_P, prec_Q); +} + +edwards_Fq6 edwards_pp::double_miller_loop(const edwards_G1_precomp &prec_P1, + const edwards_G2_precomp &prec_Q1, + const edwards_G1_precomp &prec_P2, + const edwards_G2_precomp &prec_Q2) +{ + return edwards_double_miller_loop(prec_P1, prec_Q1, prec_P2, prec_Q2); +} + +edwards_Fq6 edwards_pp::pairing(const edwards_G1 &P, + const edwards_G2 &Q) +{ + return edwards_pairing(P, Q); +} + +edwards_Fq6 edwards_pp::reduced_pairing(const edwards_G1 &P, + const edwards_G2 &Q) +{ + return edwards_reduced_pairing(P, Q); +} + +} // libsnark diff --git a/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/edwards/edwards_pp.hpp b/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/edwards/edwards_pp.hpp new file mode 100644 index 0000000..32ca85d --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/edwards/edwards_pp.hpp @@ -0,0 +1,50 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef EDWARDS_PP_HPP_ +#define EDWARDS_PP_HPP_ +#include "algebra/curves/public_params.hpp" +#include "algebra/curves/edwards/edwards_init.hpp" +#include "algebra/curves/edwards/edwards_g1.hpp" +#include "algebra/curves/edwards/edwards_g2.hpp" +#include "algebra/curves/edwards/edwards_pairing.hpp" + +namespace libsnark { + +class edwards_pp { +public: + typedef edwards_Fr Fp_type; + typedef edwards_G1 G1_type; + typedef edwards_G2 G2_type; + typedef edwards_G1_precomp G1_precomp_type; + typedef edwards_G2_precomp G2_precomp_type; + typedef edwards_Fq Fq_type; + typedef edwards_Fq3 Fqe_type; + typedef edwards_Fq6 Fqk_type; + typedef edwards_GT GT_type; + + static const bool has_affine_pairing = false; + + static void init_public_params(); + static edwards_GT final_exponentiation(const edwards_Fq6 &elt); + static edwards_G1_precomp precompute_G1(const edwards_G1 &P); + static edwards_G2_precomp precompute_G2(const edwards_G2 &Q); + static edwards_Fq6 miller_loop(const edwards_G1_precomp &prec_P, + const edwards_G2_precomp &prec_Q); + static edwards_Fq6 double_miller_loop(const edwards_G1_precomp &prec_P1, + const edwards_G2_precomp &prec_Q1, + const edwards_G1_precomp &prec_P2, + const edwards_G2_precomp &prec_Q2); + /* the following are used in test files */ + static edwards_Fq6 pairing(const edwards_G1 &P, + const edwards_G2 &Q); + static edwards_Fq6 reduced_pairing(const edwards_G1 &P, + const edwards_G2 &Q); +}; + +} // libsnark +#endif // EDWARDS_PP_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/mnt/mnt4/mnt4_g1.cpp b/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/mnt/mnt4/mnt4_g1.cpp new file mode 100644 index 0000000..8c89b02 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/mnt/mnt4/mnt4_g1.cpp @@ -0,0 +1,505 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for the MNT4 G1 group. + + See mnt4_g1.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include "algebra/curves/mnt/mnt4/mnt4_g1.hpp" + +namespace libsnark { + +#ifdef PROFILE_OP_COUNTS +long long mnt4_G1::add_cnt = 0; +long long mnt4_G1::dbl_cnt = 0; +#endif + +std::vector mnt4_G1::wnaf_window_table; +std::vector mnt4_G1::fixed_base_exp_window_table; +mnt4_G1 mnt4_G1::G1_zero; +mnt4_G1 mnt4_G1::G1_one; +mnt4_Fq mnt4_G1::coeff_a; +mnt4_Fq mnt4_G1::coeff_b; + +mnt4_G1::mnt4_G1() +{ + this->X_ = G1_zero.X_; + this->Y_ = G1_zero.Y_; + this->Z_ = G1_zero.Z_; +} + +void mnt4_G1::print() const +{ + if (this->is_zero()) + { + printf("O\n"); + } + else + { + mnt4_G1 copy(*this); + copy.to_affine_coordinates(); + gmp_printf("(%Nd , %Nd)\n", + copy.X_.as_bigint().data, mnt4_Fq::num_limbs, + copy.Y_.as_bigint().data, mnt4_Fq::num_limbs); + } +} + +void mnt4_G1::print_coordinates() const +{ + if (this->is_zero()) + { + printf("O\n"); + } + else + { + gmp_printf("(%Nd : %Nd : %Nd)\n", + this->X_.as_bigint().data, mnt4_Fq::num_limbs, + this->Y_.as_bigint().data, mnt4_Fq::num_limbs, + this->Z_.as_bigint().data, mnt4_Fq::num_limbs); + } +} + +void mnt4_G1::to_affine_coordinates() +{ + if (this->is_zero()) + { + this->X_ = mnt4_Fq::zero(); + this->Y_ = mnt4_Fq::one(); + this->Z_ = mnt4_Fq::zero(); + } + else + { + const mnt4_Fq Z_inv = Z_.inverse(); + this->X_ = this->X_ * Z_inv; + this->Y_ = this->Y_ * Z_inv; + this->Z_ = mnt4_Fq::one(); + } +} + +void mnt4_G1::to_special() +{ + this->to_affine_coordinates(); +} + +bool mnt4_G1::is_special() const +{ + return (this->is_zero() || this->Z_ == mnt4_Fq::one()); +} + +bool mnt4_G1::is_zero() const +{ + return (this->X_.is_zero() && this->Z_.is_zero()); +} + +bool mnt4_G1::operator==(const mnt4_G1 &other) const +{ + if (this->is_zero()) + { + return other.is_zero(); + } + + if (other.is_zero()) + { + return false; + } + + /* now neither is O */ + + // X1/Z1 = X2/Z2 <=> X1*Z2 = X2*Z1 + if ((this->X_ * other.Z_) != (other.X_ * this->Z_)) + { + return false; + } + + // Y1/Z1 = Y2/Z2 <=> Y1*Z2 = Y2*Z1 + if ((this->Y_ * other.Z_) != (other.Y_ * this->Z_)) + { + return false; + } + + return true; +} + +bool mnt4_G1::operator!=(const mnt4_G1& other) const +{ + return !(operator==(other)); +} + +mnt4_G1 mnt4_G1::operator+(const mnt4_G1 &other) const +{ + // handle special cases having to do with O + if (this->is_zero()) + { + return other; + } + + if (other.is_zero()) + { + return *this; + } + + // no need to handle points of order 2,4 + // (they cannot exist in a prime-order subgroup) + + // handle double case, and then all the rest + /* + The code below is equivalent to (but faster than) the snippet below: + + if (this->operator==(other)) + { + return this->dbl(); + } + else + { + return this->add(other); + } + */ + + const mnt4_Fq X1Z2 = (this->X_) * (other.Z_); // X1Z2 = X1*Z2 + const mnt4_Fq X2Z1 = (this->Z_) * (other.X_); // X2Z1 = X2*Z1 + + // (used both in add and double checks) + + const mnt4_Fq Y1Z2 = (this->Y_) * (other.Z_); // Y1Z2 = Y1*Z2 + const mnt4_Fq Y2Z1 = (this->Z_) * (other.Y_); // Y2Z1 = Y2*Z1 + + if (X1Z2 == X2Z1 && Y1Z2 == Y2Z1) + { + // perform dbl case + const mnt4_Fq XX = (this->X_).squared(); // XX = X1^2 + const mnt4_Fq ZZ = (this->Z_).squared(); // ZZ = Z1^2 + const mnt4_Fq w = mnt4_G1::coeff_a * ZZ + (XX + XX + XX); // w = a*ZZ + 3*XX + const mnt4_Fq Y1Z1 = (this->Y_) * (this->Z_); + const mnt4_Fq s = Y1Z1 + Y1Z1; // s = 2*Y1*Z1 + const mnt4_Fq ss = s.squared(); // ss = s^2 + const mnt4_Fq sss = s * ss; // sss = s*ss + const mnt4_Fq R = (this->Y_) * s; // R = Y1*s + const mnt4_Fq RR = R.squared(); // RR = R^2 + const mnt4_Fq B = ((this->X_)+R).squared()-XX-RR; // B = (X1+R)^2 - XX - RR + const mnt4_Fq h = w.squared() - (B+B); // h = w^2 - 2*B + const mnt4_Fq X3 = h * s; // X3 = h*s + const mnt4_Fq Y3 = w * (B-h)-(RR+RR); // Y3 = w*(B-h) - 2*RR + const mnt4_Fq Z3 = sss; // Z3 = sss + + return mnt4_G1(X3, Y3, Z3); + } + + // if we have arrived here we are in the add case + const mnt4_Fq Z1Z2 = (this->Z_) * (other.Z_); // Z1Z2 = Z1*Z2 + const mnt4_Fq u = Y2Z1 - Y1Z2; // u = Y2*Z1-Y1Z2 + const mnt4_Fq uu = u.squared(); // uu = u^2 + const mnt4_Fq v = X2Z1 - X1Z2; // v = X2*Z1-X1Z2 + const mnt4_Fq vv = v.squared(); // vv = v^2 + const mnt4_Fq vvv = v * vv; // vvv = v*vv + const mnt4_Fq R = vv * X1Z2; // R = vv*X1Z2 + const mnt4_Fq A = uu * Z1Z2 - (vvv + R + R); // A = uu*Z1Z2 - vvv - 2*R + const mnt4_Fq X3 = v * A; // X3 = v*A + const mnt4_Fq Y3 = u * (R-A) - vvv * Y1Z2; // Y3 = u*(R-A) - vvv*Y1Z2 + const mnt4_Fq Z3 = vvv * Z1Z2; // Z3 = vvv*Z1Z2 + + return mnt4_G1(X3, Y3, Z3); +} + +mnt4_G1 mnt4_G1::operator-() const +{ + return mnt4_G1(this->X_, -(this->Y_), this->Z_); +} + + +mnt4_G1 mnt4_G1::operator-(const mnt4_G1 &other) const +{ + return (*this) + (-other); +} + +mnt4_G1 mnt4_G1::add(const mnt4_G1 &other) const +{ + // handle special cases having to do with O + if (this->is_zero()) + { + return other; + } + + if (other.is_zero()) + { + return (*this); + } + + // no need to handle points of order 2,4 + // (they cannot exist in a prime-order subgroup) + + // handle double case + if (this->operator==(other)) + { + return this->dbl(); + } + +#ifdef PROFILE_OP_COUNTS + this->add_cnt++; +#endif + // NOTE: does not handle O and pts of order 2,4 + // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-projective.html#addition-add-1998-cmo-2 + + const mnt4_Fq Y1Z2 = (this->Y_) * (other.Z_); // Y1Z2 = Y1*Z2 + const mnt4_Fq X1Z2 = (this->X_) * (other.Z_); // X1Z2 = X1*Z2 + const mnt4_Fq Z1Z2 = (this->Z_) * (other.Z_); // Z1Z2 = Z1*Z2 + const mnt4_Fq u = (other.Y_) * (this->Z_) - Y1Z2; // u = Y2*Z1-Y1Z2 + const mnt4_Fq uu = u.squared(); // uu = u^2 + const mnt4_Fq v = (other.X_) * (this->Z_) - X1Z2; // v = X2*Z1-X1Z2 + const mnt4_Fq vv = v.squared(); // vv = v^2 + const mnt4_Fq vvv = v * vv; // vvv = v*vv + const mnt4_Fq R = vv * X1Z2; // R = vv*X1Z2 + const mnt4_Fq A = uu * Z1Z2 - (vvv + R + R); // A = uu*Z1Z2 - vvv - 2*R + const mnt4_Fq X3 = v * A; // X3 = v*A + const mnt4_Fq Y3 = u * (R-A) - vvv * Y1Z2; // Y3 = u*(R-A) - vvv*Y1Z2 + const mnt4_Fq Z3 = vvv * Z1Z2; // Z3 = vvv*Z1Z2 + + return mnt4_G1(X3, Y3, Z3); +} + +mnt4_G1 mnt4_G1::mixed_add(const mnt4_G1 &other) const +{ +#ifdef PROFILE_OP_COUNTS + this->add_cnt++; +#endif + // NOTE: does not handle O and pts of order 2,4 + // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-projective.html#addition-add-1998-cmo-2 + //assert(other.Z == mnt4_Fq::one()); + + if (this->is_zero()) + { + return other; + } + + if (other.is_zero()) + { + return (*this); + } + +#ifdef DEBUG + assert(other.is_special()); +#endif + + const mnt4_Fq &X1Z2 = (this->X_); // X1Z2 = X1*Z2 (but other is special and not zero) + const mnt4_Fq X2Z1 = (this->Z_) * (other.X_); // X2Z1 = X2*Z1 + + // (used both in add and double checks) + + const mnt4_Fq &Y1Z2 = (this->Y_); // Y1Z2 = Y1*Z2 (but other is special and not zero) + const mnt4_Fq Y2Z1 = (this->Z_) * (other.Y_); // Y2Z1 = Y2*Z1 + + if (X1Z2 == X2Z1 && Y1Z2 == Y2Z1) + { + return this->dbl(); + } + + const mnt4_Fq u = Y2Z1 - this->Y_; // u = Y2*Z1-Y1 + const mnt4_Fq uu = u.squared(); // uu = u2 + const mnt4_Fq v = X2Z1 - this->X_; // v = X2*Z1-X1 + const mnt4_Fq vv = v.squared(); // vv = v2 + const mnt4_Fq vvv = v*vv; // vvv = v*vv + const mnt4_Fq R = vv * this->X_; // R = vv*X1 + const mnt4_Fq A = uu * this->Z_ - vvv - R - R; // A = uu*Z1-vvv-2*R + const mnt4_Fq X3 = v * A; // X3 = v*A + const mnt4_Fq Y3 = u*(R-A) - vvv * this->Y_; // Y3 = u*(R-A)-vvv*Y1 + const mnt4_Fq Z3 = vvv * this->Z_; // Z3 = vvv*Z1 + + return mnt4_G1(X3, Y3, Z3); +} + +mnt4_G1 mnt4_G1::dbl() const +{ +#ifdef PROFILE_OP_COUNTS + this->dbl_cnt++; +#endif + if (this->is_zero()) + { + return (*this); + } + else + { + // NOTE: does not handle O and pts of order 2,4 + // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-projective.html#doubling-dbl-2007-bl + + const mnt4_Fq XX = (this->X_).squared(); // XX = X1^2 + const mnt4_Fq ZZ = (this->Z_).squared(); // ZZ = Z1^2 + const mnt4_Fq w = mnt4_G1::coeff_a * ZZ + (XX + XX + XX); // w = a*ZZ + 3*XX + const mnt4_Fq Y1Z1 = (this->Y_) * (this->Z_); + const mnt4_Fq s = Y1Z1 + Y1Z1; // s = 2*Y1*Z1 + const mnt4_Fq ss = s.squared(); // ss = s^2 + const mnt4_Fq sss = s * ss; // sss = s*ss + const mnt4_Fq R = (this->Y_) * s; // R = Y1*s + const mnt4_Fq RR = R.squared(); // RR = R^2 + const mnt4_Fq B = ((this->X_)+R).squared()-XX-RR; // B = (X1+R)^2 - XX - RR + const mnt4_Fq h = w.squared() - (B+B); // h = w^2 - 2*B + const mnt4_Fq X3 = h * s; // X3 = h*s + const mnt4_Fq Y3 = w * (B-h)-(RR+RR); // Y3 = w*(B-h) - 2*RR + const mnt4_Fq Z3 = sss; // Z3 = sss + + return mnt4_G1(X3, Y3, Z3); + } +} + +bool mnt4_G1::is_well_formed() const +{ + if (this->is_zero()) + { + return true; + } + else + { + /* + y^2 = x^3 + ax + b + + We are using projective, so equation we need to check is actually + + (y/z)^2 = (x/z)^3 + a (x/z) + b + z y^2 = x^3 + a z^2 x + b z^3 + + z (y^2 - b z^2) = x ( x^2 + a z^2) + */ + const mnt4_Fq X2 = this->X_.squared(); + const mnt4_Fq Y2 = this->Y_.squared(); + const mnt4_Fq Z2 = this->Z_.squared(); + + return (this->Z_ * (Y2 - mnt4_G1::coeff_b * Z2) == this->X_ * (X2 + mnt4_G1::coeff_a * Z2)); + } +} + +mnt4_G1 mnt4_G1::zero() +{ + return G1_zero; +} + +mnt4_G1 mnt4_G1::one() +{ + return G1_one; +} + +mnt4_G1 mnt4_G1::random_element() +{ + return (scalar_field::random_element().as_bigint()) * G1_one; +} + +std::ostream& operator<<(std::ostream &out, const mnt4_G1 &g) +{ + mnt4_G1 copy(g); + copy.to_affine_coordinates(); + + out << (copy.is_zero() ? 1 : 0) << OUTPUT_SEPARATOR; +#ifdef NO_PT_COMPRESSION + out << copy.X_ << OUTPUT_SEPARATOR << copy.Y_; +#else + /* storing LSB of Y */ + out << copy.X_ << OUTPUT_SEPARATOR << (copy.Y_.as_bigint().data[0] & 1); +#endif + + return out; +} + +std::istream& operator>>(std::istream &in, mnt4_G1 &g) +{ + char is_zero; + mnt4_Fq tX, tY; + +#ifdef NO_PT_COMPRESSION + in >> is_zero >> tX >> tY; + is_zero -= '0'; +#else + in.read((char*)&is_zero, 1); + is_zero -= '0'; + consume_OUTPUT_SEPARATOR(in); + + unsigned char Y_lsb; + in >> tX; + consume_OUTPUT_SEPARATOR(in); + in.read((char*)&Y_lsb, 1); + Y_lsb -= '0'; + + // y = +/- sqrt(x^3 + a*x + b) + if (!is_zero) + { + mnt4_Fq tX2 = tX.squared(); + mnt4_Fq tY2 = (tX2 + mnt4_G1::coeff_a) * tX + mnt4_G1::coeff_b; + tY = tY2.sqrt(); + + if ((tY.as_bigint().data[0] & 1) != Y_lsb) + { + tY = -tY; + } + } +#endif + // using projective coordinates + if (!is_zero) + { + g.X_ = tX; + g.Y_ = tY; + g.Z_ = mnt4_Fq::one(); + } + else + { + g = mnt4_G1::zero(); + } + + return in; +} + +std::ostream& operator<<(std::ostream& out, const std::vector &v) +{ + out << v.size() << "\n"; + for (const mnt4_G1& t : v) + { + out << t << OUTPUT_NEWLINE; + } + + return out; +} + +std::istream& operator>>(std::istream& in, std::vector &v) +{ + v.clear(); + + size_t s; + in >> s; + + consume_newline(in); + + v.reserve(s); + + for (size_t i = 0; i < s; ++i) + { + mnt4_G1 g; + in >> g; + consume_OUTPUT_NEWLINE(in); + v.emplace_back(g); + } + + return in; +} + +template<> +void batch_to_special_all_non_zeros(std::vector &vec) +{ + std::vector Z_vec; + Z_vec.reserve(vec.size()); + + for (auto &el: vec) + { + Z_vec.emplace_back(el.Z()); + } + batch_invert(Z_vec); + + const mnt4_Fq one = mnt4_Fq::one(); + + for (size_t i = 0; i < vec.size(); ++i) + { + vec[i] = mnt4_G1(vec[i].X() * Z_vec[i], vec[i].Y() * Z_vec[i], one); + } +} + +} // libsnark diff --git a/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/mnt/mnt4/mnt4_g1.hpp b/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/mnt/mnt4/mnt4_g1.hpp new file mode 100644 index 0000000..19e77bd --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/mnt/mnt4/mnt4_g1.hpp @@ -0,0 +1,109 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for the MNT4 G1 group. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef MNT4_G1_HPP_ +#define MNT4_G1_HPP_ + +#include + +#include "algebra/curves/curve_utils.hpp" +#include "algebra/curves/mnt/mnt4/mnt4_init.hpp" + +namespace libsnark { + +class mnt4_G1; +std::ostream& operator<<(std::ostream &, const mnt4_G1&); +std::istream& operator>>(std::istream &, mnt4_G1&); + +class mnt4_G1 { +private: + mnt4_Fq X_, Y_, Z_; +public: +#ifdef PROFILE_OP_COUNTS + static long long add_cnt; + static long long dbl_cnt; +#endif + static std::vector wnaf_window_table; + static std::vector fixed_base_exp_window_table; + static mnt4_G1 G1_zero; + static mnt4_G1 G1_one; + static mnt4_Fq coeff_a; + static mnt4_Fq coeff_b; + + typedef mnt4_Fq base_field; + typedef mnt4_Fr scalar_field; + + // using projective coordinates + mnt4_G1(); + mnt4_G1(const mnt4_Fq& X, const mnt4_Fq& Y) : X_(X), Y_(Y), Z_(base_field::one()) {} + mnt4_G1(const mnt4_Fq& X, const mnt4_Fq& Y, const mnt4_Fq& Z) : X_(X), Y_(Y), Z_(Z) {} + + mnt4_Fq X() const { return X_; } + mnt4_Fq Y() const { return Y_; } + mnt4_Fq Z() const { return Z_; } + + void print() const; + void print_coordinates() const; + + void to_affine_coordinates(); + void to_special(); + bool is_special() const; + + bool is_zero() const; + + bool operator==(const mnt4_G1 &other) const; + bool operator!=(const mnt4_G1 &other) const; + + mnt4_G1 operator+(const mnt4_G1 &other) const; + mnt4_G1 operator-() const; + mnt4_G1 operator-(const mnt4_G1 &other) const; + + mnt4_G1 add(const mnt4_G1 &other) const; + mnt4_G1 mixed_add(const mnt4_G1 &other) const; + mnt4_G1 dbl() const; + + bool is_well_formed() const; + + static mnt4_G1 zero(); + static mnt4_G1 one(); + static mnt4_G1 random_element(); + + static size_t size_in_bits() { return mnt4_Fq::size_in_bits() + 1; } + static bigint base_field_char() { return mnt4_Fq::field_char(); } + static bigint order() { return mnt4_Fr::field_char(); } + + friend std::ostream& operator<<(std::ostream &out, const mnt4_G1 &g); + friend std::istream& operator>>(std::istream &in, mnt4_G1 &g); +}; + +template +mnt4_G1 operator*(const bigint &lhs, const mnt4_G1 &rhs) +{ + return scalar_mul(rhs, lhs); +} + +template& modulus_p> +mnt4_G1 operator*(const Fp_model &lhs, const mnt4_G1 &rhs) +{ + return scalar_mul(rhs, lhs.as_bigint()); +} + +std::ostream& operator<<(std::ostream& out, const std::vector &v); +std::istream& operator>>(std::istream& in, std::vector &v); + +template +void batch_to_special_all_non_zeros(std::vector &vec); +template<> +void batch_to_special_all_non_zeros(std::vector &vec); + +} // libsnark + +#endif // MNT4_G1_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/mnt/mnt4/mnt4_g2.cpp b/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/mnt/mnt4/mnt4_g2.cpp new file mode 100644 index 0000000..d1da1fc --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/mnt/mnt4/mnt4_g2.cpp @@ -0,0 +1,496 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for the MNT4 G2 group. + + See mnt4_g2.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include "algebra/curves/mnt/mnt4/mnt4_g2.hpp" + +namespace libsnark { + +#ifdef PROFILE_OP_COUNTS +long long mnt4_G2::add_cnt = 0; +long long mnt4_G2::dbl_cnt = 0; +#endif + +std::vector mnt4_G2::wnaf_window_table; +std::vector mnt4_G2::fixed_base_exp_window_table; +mnt4_Fq2 mnt4_G2::twist; +mnt4_Fq2 mnt4_G2::coeff_a; +mnt4_Fq2 mnt4_G2::coeff_b; +mnt4_G2 mnt4_G2::G2_zero; +mnt4_G2 mnt4_G2::G2_one; + +mnt4_Fq2 mnt4_G2::mul_by_a(const mnt4_Fq2 &elt) +{ + return mnt4_Fq2(mnt4_twist_mul_by_a_c0 * elt.c0, mnt4_twist_mul_by_a_c1 * elt.c1); +} + +mnt4_Fq2 mnt4_G2::mul_by_b(const mnt4_Fq2 &elt) +{ + return mnt4_Fq2(mnt4_twist_mul_by_b_c0 * elt.c1, mnt4_twist_mul_by_b_c1 * elt.c0); +} + +mnt4_G2::mnt4_G2() +{ + this->X_ = G2_zero.X_; + this->Y_ = G2_zero.Y_; + this->Z_ = G2_zero.Z_; +} + +void mnt4_G2::print() const +{ + if (this->is_zero()) + { + printf("O\n"); + } + else + { + mnt4_G2 copy(*this); + copy.to_affine_coordinates(); + gmp_printf("(%Nd*z + %Nd , %Nd*z + %Nd)\n", + copy.X_.c1.as_bigint().data, mnt4_Fq::num_limbs, + copy.X_.c0.as_bigint().data, mnt4_Fq::num_limbs, + copy.Y_.c1.as_bigint().data, mnt4_Fq::num_limbs, + copy.Y_.c0.as_bigint().data, mnt4_Fq::num_limbs); + } +} + +void mnt4_G2::print_coordinates() const +{ + if (this->is_zero()) + { + printf("O\n"); + } + else + { + gmp_printf("(%Nd*z + %Nd : %Nd*z + %Nd : %Nd*z + %Nd)\n", + this->X_.c1.as_bigint().data, mnt4_Fq::num_limbs, + this->X_.c0.as_bigint().data, mnt4_Fq::num_limbs, + this->Y_.c1.as_bigint().data, mnt4_Fq::num_limbs, + this->Y_.c0.as_bigint().data, mnt4_Fq::num_limbs, + this->Z_.c1.as_bigint().data, mnt4_Fq::num_limbs, + this->Z_.c0.as_bigint().data, mnt4_Fq::num_limbs); + } +} + +void mnt4_G2::to_affine_coordinates() +{ + if (this->is_zero()) + { + this->X_ = mnt4_Fq2::zero(); + this->Y_ = mnt4_Fq2::one(); + this->Z_ = mnt4_Fq2::zero(); + } + else + { + const mnt4_Fq2 Z_inv = Z_.inverse(); + X_ = X_ * Z_inv; + Y_ = Y_ * Z_inv; + Z_ = mnt4_Fq2::one(); + } +} + +void mnt4_G2::to_special() +{ + this->to_affine_coordinates(); +} + +bool mnt4_G2::is_special() const +{ + return (this->is_zero() || this->Z_ == mnt4_Fq2::one()); +} + +bool mnt4_G2::is_zero() const +{ + return (this->X_.is_zero() && this->Z_.is_zero()); +} + +bool mnt4_G2::operator==(const mnt4_G2 &other) const +{ + if (this->is_zero()) + { + return other.is_zero(); + } + + if (other.is_zero()) + { + return false; + } + + /* now neither is O */ + + // X1/Z1 = X2/Z2 <=> X1*Z2 = X2*Z1 + if ((this->X_ * other.Z_) != (other.X_ * this->Z_)) + { + return false; + } + + // Y1/Z1 = Y2/Z2 <=> Y1*Z2 = Y2*Z1 + if ((this->Y_ * other.Z_) != (other.Y_ * this->Z_)) + { + return false; + } + + return true; +} + +bool mnt4_G2::operator!=(const mnt4_G2& other) const +{ + return !(operator==(other)); +} + +mnt4_G2 mnt4_G2::operator+(const mnt4_G2 &other) const +{ + // handle special cases having to do with O + if (this->is_zero()) + { + return other; + } + + if (other.is_zero()) + { + return *this; + } + + // no need to handle points of order 2,4 + // (they cannot exist in a prime-order subgroup) + + // handle double case, and then all the rest + /* + The code below is equivalent to (but faster than) the snippet below: + + if (this->operator==(other)) + { + return this->dbl(); + } + else + { + return this->add(other); + } + */ + + const mnt4_Fq2 X1Z2 = (this->X_) * (other.Z_); // X1Z2 = X1*Z2 + const mnt4_Fq2 X2Z1 = (this->Z_) * (other.X_); // X2Z1 = X2*Z1 + + // (used both in add and double checks) + + const mnt4_Fq2 Y1Z2 = (this->Y_) * (other.Z_); // Y1Z2 = Y1*Z2 + const mnt4_Fq2 Y2Z1 = (this->Z_) * (other.Y_); // Y2Z1 = Y2*Z1 + + if (X1Z2 == X2Z1 && Y1Z2 == Y2Z1) + { + // perform dbl case + const mnt4_Fq2 XX = (this->X_).squared(); // XX = X1^2 + const mnt4_Fq2 ZZ = (this->Z_).squared(); // ZZ = Z1^2 + const mnt4_Fq2 w = mnt4_G2::mul_by_a(ZZ) + (XX + XX + XX); // w = a*ZZ + 3*XX + const mnt4_Fq2 Y1Z1 = (this->Y_) * (this->Z_); + const mnt4_Fq2 s = Y1Z1 + Y1Z1; // s = 2*Y1*Z1 + const mnt4_Fq2 ss = s.squared(); // ss = s^2 + const mnt4_Fq2 sss = s * ss; // sss = s*ss + const mnt4_Fq2 R = (this->Y_) * s; // R = Y1*s + const mnt4_Fq2 RR = R.squared(); // RR = R^2 + const mnt4_Fq2 B = ((this->X_)+R).squared()-XX-RR; // B = (X1+R)^2 - XX - RR + const mnt4_Fq2 h = w.squared() - (B+B); // h = w^2 - 2*B + const mnt4_Fq2 X3 = h * s; // X3 = h*s + const mnt4_Fq2 Y3 = w * (B-h)-(RR+RR); // Y3 = w*(B-h) - 2*RR + const mnt4_Fq2 Z3 = sss; // Z3 = sss + + return mnt4_G2(X3, Y3, Z3); + } + + // if we have arrived here we are in the add case + const mnt4_Fq2 Z1Z2 = (this->Z_) * (other.Z_); // Z1Z2 = Z1*Z2 + const mnt4_Fq2 u = Y2Z1 - Y1Z2; // u = Y2*Z1-Y1Z2 + const mnt4_Fq2 uu = u.squared(); // uu = u^2 + const mnt4_Fq2 v = X2Z1 - X1Z2; // v = X2*Z1-X1Z2 + const mnt4_Fq2 vv = v.squared(); // vv = v^2 + const mnt4_Fq2 vvv = v * vv; // vvv = v*vv + const mnt4_Fq2 R = vv * X1Z2; // R = vv*X1Z2 + const mnt4_Fq2 A = uu * Z1Z2 - (vvv + R + R); // A = uu*Z1Z2 - vvv - 2*R + const mnt4_Fq2 X3 = v * A; // X3 = v*A + const mnt4_Fq2 Y3 = u * (R-A) - vvv * Y1Z2; // Y3 = u*(R-A) - vvv*Y1Z2 + const mnt4_Fq2 Z3 = vvv * Z1Z2; // Z3 = vvv*Z1Z2 + + return mnt4_G2(X3, Y3, Z3); +} + +mnt4_G2 mnt4_G2::operator-() const +{ + return mnt4_G2(this->X_, -(this->Y_), this->Z_); +} + + +mnt4_G2 mnt4_G2::operator-(const mnt4_G2 &other) const +{ + return (*this) + (-other); +} + +mnt4_G2 mnt4_G2::add(const mnt4_G2 &other) const +{ + // handle special cases having to do with O + if (this->is_zero()) + { + return other; + } + + if (other.is_zero()) + { + return (*this); + } + + // no need to handle points of order 2,4 + // (they cannot exist in a prime-order subgroup) + + // handle double case + if (this->operator==(other)) + { + return this->dbl(); + } + +#ifdef PROFILE_OP_COUNTS + this->add_cnt++; +#endif + // NOTE: does not handle O and pts of order 2,4 + // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-projective.html#addition-add-1998-cmo-2 + + const mnt4_Fq2 Y1Z2 = (this->Y_) * (other.Z_); // Y1Z2 = Y1*Z2 + const mnt4_Fq2 X1Z2 = (this->X_) * (other.Z_); // X1Z2 = X1*Z2 + const mnt4_Fq2 Z1Z2 = (this->Z_) * (other.Z_); // Z1Z2 = Z1*Z2 + const mnt4_Fq2 u = (other.Y_) * (this->Z_) - Y1Z2; // u = Y2*Z1-Y1Z2 + const mnt4_Fq2 uu = u.squared(); // uu = u^2 + const mnt4_Fq2 v = (other.X_) * (this->Z_) - X1Z2; // v = X2*Z1-X1Z2 + const mnt4_Fq2 vv = v.squared(); // vv = v^2 + const mnt4_Fq2 vvv = v * vv; // vvv = v*vv + const mnt4_Fq2 R = vv * X1Z2; // R = vv*X1Z2 + const mnt4_Fq2 A = uu * Z1Z2 - (vvv + R + R); // A = uu*Z1Z2 - vvv - 2*R + const mnt4_Fq2 X3 = v * A; // X3 = v*A + const mnt4_Fq2 Y3 = u * (R-A) - vvv * Y1Z2; // Y3 = u*(R-A) - vvv*Y1Z2 + const mnt4_Fq2 Z3 = vvv * Z1Z2; // Z3 = vvv*Z1Z2 + + return mnt4_G2(X3, Y3, Z3); +} + +mnt4_G2 mnt4_G2::mixed_add(const mnt4_G2 &other) const +{ +#ifdef PROFILE_OP_COUNTS + this->add_cnt++; +#endif + // NOTE: does not handle O and pts of order 2,4 + // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-projective.html#addition-add-1998-cmo-2 + //assert(other.Z == mnt4_Fq2::one()); + + if (this->is_zero()) + { + return other; + } + + if (other.is_zero()) + { + return (*this); + } + +#ifdef DEBUG + assert(other.is_special()); +#endif + + const mnt4_Fq2 &X1Z2 = (this->X_); // X1Z2 = X1*Z2 (but other is special and not zero) + const mnt4_Fq2 X2Z1 = (this->Z_) * (other.X_); // X2Z1 = X2*Z1 + + // (used both in add and double checks) + + const mnt4_Fq2 &Y1Z2 = (this->Y_); // Y1Z2 = Y1*Z2 (but other is special and not zero) + const mnt4_Fq2 Y2Z1 = (this->Z_) * (other.Y_); // Y2Z1 = Y2*Z1 + + if (X1Z2 == X2Z1 && Y1Z2 == Y2Z1) + { + return this->dbl(); + } + + const mnt4_Fq2 u = Y2Z1 - this->Y_; // u = Y2*Z1-Y1 + const mnt4_Fq2 uu = u.squared(); // uu = u2 + const mnt4_Fq2 v = X2Z1 - this->X_; // v = X2*Z1-X1 + const mnt4_Fq2 vv = v.squared(); // vv = v2 + const mnt4_Fq2 vvv = v*vv; // vvv = v*vv + const mnt4_Fq2 R = vv * this->X_; // R = vv*X1 + const mnt4_Fq2 A = uu * this->Z_ - vvv - R - R; // A = uu*Z1-vvv-2*R + const mnt4_Fq2 X3 = v * A; // X3 = v*A + const mnt4_Fq2 Y3 = u*(R-A) - vvv * this->Y_; // Y3 = u*(R-A)-vvv*Y1 + const mnt4_Fq2 Z3 = vvv * this->Z_; // Z3 = vvv*Z1 + + return mnt4_G2(X3, Y3, Z3); +} + +mnt4_G2 mnt4_G2::dbl() const +{ +#ifdef PROFILE_OP_COUNTS + this->dbl_cnt++; +#endif + if (this->is_zero()) + { + return (*this); + } + else + { + // NOTE: does not handle O and pts of order 2,4 + // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-projective.html#doubling-dbl-2007-bl + + const mnt4_Fq2 XX = (this->X_).squared(); // XX = X1^2 + const mnt4_Fq2 ZZ = (this->Z_).squared(); // ZZ = Z1^2 + const mnt4_Fq2 w = mnt4_G2::mul_by_a(ZZ) + (XX + XX + XX); // w = a*ZZ + 3*XX + const mnt4_Fq2 Y1Z1 = (this->Y_) * (this->Z_); + const mnt4_Fq2 s = Y1Z1 + Y1Z1; // s = 2*Y1*Z1 + const mnt4_Fq2 ss = s.squared(); // ss = s^2 + const mnt4_Fq2 sss = s * ss; // sss = s*ss + const mnt4_Fq2 R = (this->Y_) * s; // R = Y1*s + const mnt4_Fq2 RR = R.squared(); // RR = R^2 + const mnt4_Fq2 B = ((this->X_)+R).squared()-XX-RR; // B = (X1+R)^2 - XX - RR + const mnt4_Fq2 h = w.squared() - (B+B); // h = w^2-2*B + const mnt4_Fq2 X3 = h * s; // X3 = h*s + const mnt4_Fq2 Y3 = w * (B-h)-(RR+RR); // Y3 = w*(B-h) - 2*RR + const mnt4_Fq2 Z3 = sss; // Z3 = sss + + return mnt4_G2(X3, Y3, Z3); + } +} + +mnt4_G2 mnt4_G2::mul_by_q() const +{ + return mnt4_G2(mnt4_twist_mul_by_q_X * (this->X_).Frobenius_map(1), + mnt4_twist_mul_by_q_Y * (this->Y_).Frobenius_map(1), + (this->Z_).Frobenius_map(1)); +} + +bool mnt4_G2::is_well_formed() const +{ + if (this->is_zero()) + { + return true; + } + else + { + /* + y^2 = x^3 + ax + b + + We are using projective, so equation we need to check is actually + + (y/z)^2 = (x/z)^3 + a (x/z) + b + z y^2 = x^3 + a z^2 x + b z^3 + + z (y^2 - b z^2) = x ( x^2 + a z^2) + */ + const mnt4_Fq2 X2 = this->X_.squared(); + const mnt4_Fq2 Y2 = this->Y_.squared(); + const mnt4_Fq2 Z2 = this->Z_.squared(); + const mnt4_Fq2 aZ2 = mnt4_twist_coeff_a * Z2; + + return (this->Z_ * (Y2 - mnt4_twist_coeff_b * Z2) == this->X_ * (X2 + aZ2)); + } +} + +mnt4_G2 mnt4_G2::zero() +{ + return G2_zero; +} + +mnt4_G2 mnt4_G2::one() +{ + return G2_one; +} + +mnt4_G2 mnt4_G2::random_element() +{ + return (mnt4_Fr::random_element().as_bigint()) * G2_one; +} + +std::ostream& operator<<(std::ostream &out, const mnt4_G2 &g) +{ + mnt4_G2 copy(g); + copy.to_affine_coordinates(); + + out << (copy.is_zero() ? 1 : 0) << OUTPUT_SEPARATOR; +#ifdef NO_PT_COMPRESSION + out << copy.X_ << OUTPUT_SEPARATOR << copy.Y_; +#else + /* storing LSB of Y */ + out << copy.X_ << OUTPUT_SEPARATOR << (copy.Y_.c0.as_bigint().data[0] & 1); +#endif + + return out; +} + +std::istream& operator>>(std::istream &in, mnt4_G2 &g) +{ + char is_zero; + mnt4_Fq2 tX, tY; + +#ifdef NO_PT_COMPRESSION + in >> is_zero >> tX >> tY; + is_zero -= '0'; +#else + in.read((char*)&is_zero, 1); // this reads is_zero; + is_zero -= '0'; + consume_OUTPUT_SEPARATOR(in); + + unsigned char Y_lsb; + in >> tX; + consume_OUTPUT_SEPARATOR(in); + in.read((char*)&Y_lsb, 1); + Y_lsb -= '0'; + + // y = +/- sqrt(x^3 + a*x + b) + if (!is_zero) + { + mnt4_Fq2 tX2 = tX.squared(); + mnt4_Fq2 tY2 = (tX2 + mnt4_twist_coeff_a ) * tX + mnt4_twist_coeff_b; + tY = tY2.sqrt(); + + if ((tY.c0.as_bigint().data[0] & 1) != Y_lsb) + { + tY = -tY; + } + } +#endif + // using projective coordinates + if (!is_zero) + { + g.X_ = tX; + g.Y_ = tY; + g.Z_ = mnt4_Fq2::one(); + } + else + { + g = mnt4_G2::zero(); + } + + return in; +} + +template<> +void batch_to_special_all_non_zeros(std::vector &vec) +{ + std::vector Z_vec; + Z_vec.reserve(vec.size()); + + for (auto &el: vec) + { + Z_vec.emplace_back(el.Z()); + } + batch_invert(Z_vec); + + const mnt4_Fq2 one = mnt4_Fq2::one(); + + for (size_t i = 0; i < vec.size(); ++i) + { + vec[i] = mnt4_G2(vec[i].X() * Z_vec[i], vec[i].Y() * Z_vec[i], one); + } +} + +} // libsnark diff --git a/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/mnt/mnt4/mnt4_g2.hpp b/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/mnt/mnt4/mnt4_g2.hpp new file mode 100644 index 0000000..47fccca --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/mnt/mnt4/mnt4_g2.hpp @@ -0,0 +1,111 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for the MNT4 G2 group. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef MNT4_G2_HPP_ +#define MNT4_G2_HPP_ + +#include + +#include "algebra/curves/curve_utils.hpp" +#include "algebra/curves/mnt/mnt4/mnt4_init.hpp" + +namespace libsnark { + +class mnt4_G2; +std::ostream& operator<<(std::ostream &, const mnt4_G2&); +std::istream& operator>>(std::istream &, mnt4_G2&); + +class mnt4_G2 { +private: + mnt4_Fq2 X_, Y_, Z_; +public: +#ifdef PROFILE_OP_COUNTS + static long long add_cnt; + static long long dbl_cnt; +#endif + static std::vector wnaf_window_table; + static std::vector fixed_base_exp_window_table; + static mnt4_G2 G2_zero; + static mnt4_G2 G2_one; + static mnt4_Fq2 twist; + static mnt4_Fq2 coeff_a; + static mnt4_Fq2 coeff_b; + + typedef mnt4_Fq base_field; + typedef mnt4_Fq2 twist_field; + typedef mnt4_Fr scalar_field; + + // using projective coordinates + mnt4_G2(); + mnt4_G2(const mnt4_Fq2& X, const mnt4_Fq2& Y, const mnt4_Fq2& Z) : X_(X), Y_(Y), Z_(Z) {}; + + mnt4_Fq2 X() const { return X_; } + mnt4_Fq2 Y() const { return Y_; } + mnt4_Fq2 Z() const { return Z_; } + + static mnt4_Fq2 mul_by_a(const mnt4_Fq2 &elt); + static mnt4_Fq2 mul_by_b(const mnt4_Fq2 &elt); + + void print() const; + void print_coordinates() const; + + void to_affine_coordinates(); + void to_special(); + bool is_special() const; + + bool is_zero() const; + + bool operator==(const mnt4_G2 &other) const; + bool operator!=(const mnt4_G2 &other) const; + + mnt4_G2 operator+(const mnt4_G2 &other) const; + mnt4_G2 operator-() const; + mnt4_G2 operator-(const mnt4_G2 &other) const; + + mnt4_G2 add(const mnt4_G2 &other) const; + mnt4_G2 mixed_add(const mnt4_G2 &other) const; + mnt4_G2 dbl() const; + mnt4_G2 mul_by_q() const; + + bool is_well_formed() const; + + static mnt4_G2 zero(); + static mnt4_G2 one(); + static mnt4_G2 random_element(); + + static size_t size_in_bits() { return mnt4_Fq2::size_in_bits() + 1; } + static bigint base_field_char() { return mnt4_Fq::field_char(); } + static bigint order() { return mnt4_Fr::field_char(); } + + friend std::ostream& operator<<(std::ostream &out, const mnt4_G2 &g); + friend std::istream& operator>>(std::istream &in, mnt4_G2 &g); +}; + +template +mnt4_G2 operator*(const bigint &lhs, const mnt4_G2 &rhs) +{ + return scalar_mul(rhs, lhs); +} + +template& modulus_p> +mnt4_G2 operator*(const Fp_model &lhs, const mnt4_G2 &rhs) +{ + return scalar_mul(rhs, lhs.as_bigint()); +} + +template +void batch_to_special_all_non_zeros(std::vector &vec); +template<> +void batch_to_special_all_non_zeros(std::vector &vec); + +} // libsnark + +#endif // MNT4_G2_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/mnt/mnt4/mnt4_init.cpp b/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/mnt/mnt4/mnt4_init.cpp new file mode 100644 index 0000000..4d480ed --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/mnt/mnt4/mnt4_init.cpp @@ -0,0 +1,265 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for initializing MNT4. + + See mnt4_init.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include "algebra/curves/mnt/mnt4/mnt4_init.hpp" +#include "algebra/curves/mnt/mnt4/mnt4_g1.hpp" +#include "algebra/curves/mnt/mnt4/mnt4_g2.hpp" + +namespace libsnark { + +// bigint mnt4_modulus_r = mnt46_modulus_A; +// bigint mnt4_modulus_q = mnt46_modulus_B; + +mnt4_Fq2 mnt4_twist; +mnt4_Fq2 mnt4_twist_coeff_a; +mnt4_Fq2 mnt4_twist_coeff_b; +mnt4_Fq mnt4_twist_mul_by_a_c0; +mnt4_Fq mnt4_twist_mul_by_a_c1; +mnt4_Fq mnt4_twist_mul_by_b_c0; +mnt4_Fq mnt4_twist_mul_by_b_c1; +mnt4_Fq mnt4_twist_mul_by_q_X; +mnt4_Fq mnt4_twist_mul_by_q_Y; + +bigint mnt4_ate_loop_count; +bool mnt4_ate_is_loop_count_neg; +bigint<4*mnt4_q_limbs> mnt4_final_exponent; +bigint mnt4_final_exponent_last_chunk_abs_of_w0; +bool mnt4_final_exponent_last_chunk_is_w0_neg; +bigint mnt4_final_exponent_last_chunk_w1; + +void init_mnt4_params() +{ + typedef bigint bigint_r; + typedef bigint bigint_q; + + assert(sizeof(mp_limb_t) == 8 || sizeof(mp_limb_t) == 4); // Montgomery assumes this + + /* parameters for scalar field Fr */ + mnt4_modulus_r = bigint_r("475922286169261325753349249653048451545124878552823515553267735739164647307408490559963137"); + assert(mnt4_Fr::modulus_is_valid()); + if (sizeof(mp_limb_t) == 8) + { + mnt4_Fr::Rsquared = bigint_r("163983144722506446826715124368972380525894397127205577781234305496325861831001705438796139"); + mnt4_Fr::Rcubed = bigint_r("207236281459091063710247635236340312578688659363066707916716212805695955118593239854980171"); + mnt4_Fr::inv = 0xbb4334a3ffffffff; + } + if (sizeof(mp_limb_t) == 4) + { + mnt4_Fr::Rsquared = bigint_r("163983144722506446826715124368972380525894397127205577781234305496325861831001705438796139"); + mnt4_Fr::Rcubed = bigint_r("207236281459091063710247635236340312578688659363066707916716212805695955118593239854980171"); + mnt4_Fr::inv = 0xffffffff; + } + mnt4_Fr::num_bits = 298; + mnt4_Fr::euler = bigint_r("237961143084630662876674624826524225772562439276411757776633867869582323653704245279981568"); + mnt4_Fr::s = 34; + mnt4_Fr::t = bigint_r("27702323054502562488973446286577291993024111641153199339359284829066871159442729"); + mnt4_Fr::t_minus_1_over_2 = bigint_r("13851161527251281244486723143288645996512055820576599669679642414533435579721364"); + mnt4_Fr::multiplicative_generator = mnt4_Fr("10"); + mnt4_Fr::root_of_unity = mnt4_Fr("120638817826913173458768829485690099845377008030891618010109772937363554409782252579816313"); + mnt4_Fr::nqr = mnt4_Fr("5"); + mnt4_Fr::nqr_to_t = mnt4_Fr("406220604243090401056429458730298145937262552508985450684842547562990900634752279902740880"); + + /* parameters for base field Fq */ + mnt4_modulus_q = bigint_q("475922286169261325753349249653048451545124879242694725395555128576210262817955800483758081"); + assert(mnt4_Fq::modulus_is_valid()); + if (sizeof(mp_limb_t) == 8) + { + mnt4_Fq::Rsquared = bigint_q("273000478523237720910981655601160860640083126627235719712980612296263966512828033847775776"); + mnt4_Fq::Rcubed = bigint_q("427298980065529822574935274648041073124704261331681436071990730954930769758106792920349077"); + mnt4_Fq::inv = 0xb071a1b67165ffff; + } + if (sizeof(mp_limb_t) == 4) + { + mnt4_Fq::Rsquared = bigint_q("273000478523237720910981655601160860640083126627235719712980612296263966512828033847775776"); + mnt4_Fq::Rcubed = bigint_q("427298980065529822574935274648041073124704261331681436071990730954930769758106792920349077"); + mnt4_Fq::inv = 0x7165ffff; + } + mnt4_Fq::num_bits = 298; + mnt4_Fq::euler = bigint_q("237961143084630662876674624826524225772562439621347362697777564288105131408977900241879040"); + mnt4_Fq::s = 17; + mnt4_Fq::t = bigint_q("3630998887399759870554727551674258816109656366292531779446068791017229177993437198515"); + mnt4_Fq::t_minus_1_over_2 = bigint_q("1815499443699879935277363775837129408054828183146265889723034395508614588996718599257"); + mnt4_Fq::multiplicative_generator = mnt4_Fq("17"); + mnt4_Fq::root_of_unity = mnt4_Fq("264706250571800080758069302369654305530125675521263976034054878017580902343339784464690243"); + mnt4_Fq::nqr = mnt4_Fq("17"); + mnt4_Fq::nqr_to_t = mnt4_Fq("264706250571800080758069302369654305530125675521263976034054878017580902343339784464690243"); + + /* parameters for twist field Fq2 */ + mnt4_Fq2::euler = bigint<2*mnt4_q_limbs>("113251011236288135098249345249154230895914381858788918106847214243419142422924133497460817468249854833067260038985710370091920860837014281886963086681184370139950267830740466401280"); + mnt4_Fq2::s = 18; + mnt4_Fq2::t = bigint<2*mnt4_q_limbs>("864036645784668999467844736092790457885088972921668381552484239528039111503022258739172496553419912972009735404859240494475714575477709059806542104196047745818712370534824115"); + mnt4_Fq2::t_minus_1_over_2 = bigint<2*mnt4_q_limbs>("432018322892334499733922368046395228942544486460834190776242119764019555751511129369586248276709956486004867702429620247237857287738854529903271052098023872909356185267412057"); + mnt4_Fq2::non_residue = mnt4_Fq("17"); + mnt4_Fq2::nqr = mnt4_Fq2(mnt4_Fq("8"),mnt4_Fq("1")); + mnt4_Fq2::nqr_to_t = mnt4_Fq2(mnt4_Fq("0"),mnt4_Fq("29402818985595053196743631544512156561638230562612542604956687802791427330205135130967658")); + mnt4_Fq2::Frobenius_coeffs_c1[0] = mnt4_Fq("1"); + mnt4_Fq2::Frobenius_coeffs_c1[1] = mnt4_Fq("475922286169261325753349249653048451545124879242694725395555128576210262817955800483758080"); + + /* parameters for Fq4 */ + mnt4_Fq4::non_residue = mnt4_Fq("17"); + mnt4_Fq4::Frobenius_coeffs_c1[0] = mnt4_Fq("1"); + mnt4_Fq4::Frobenius_coeffs_c1[1] = mnt4_Fq("7684163245453501615621351552473337069301082060976805004625011694147890954040864167002308"); + mnt4_Fq4::Frobenius_coeffs_c1[2] = mnt4_Fq("475922286169261325753349249653048451545124879242694725395555128576210262817955800483758080"); + mnt4_Fq4::Frobenius_coeffs_c1[3] = mnt4_Fq("468238122923807824137727898100575114475823797181717920390930116882062371863914936316755773"); + + /* choice of short Weierstrass curve and its twist */ + mnt4_G1::coeff_a = mnt4_Fq("2"); + mnt4_G1::coeff_b = mnt4_Fq("423894536526684178289416011533888240029318103673896002803341544124054745019340795360841685"); + mnt4_twist = mnt4_Fq2(mnt4_Fq::zero(), mnt4_Fq::one()); + mnt4_twist_coeff_a = mnt4_Fq2(mnt4_G1::coeff_a * mnt4_Fq2::non_residue, mnt4_Fq::zero()); + mnt4_twist_coeff_b = mnt4_Fq2(mnt4_Fq::zero(), mnt4_G1::coeff_b * mnt4_Fq2::non_residue); + mnt4_G2::twist = mnt4_twist; + mnt4_G2::coeff_a = mnt4_twist_coeff_a; + mnt4_G2::coeff_b = mnt4_twist_coeff_b; + mnt4_twist_mul_by_a_c0 = mnt4_G1::coeff_a * mnt4_Fq2::non_residue; + mnt4_twist_mul_by_a_c1 = mnt4_G1::coeff_a * mnt4_Fq2::non_residue; + mnt4_twist_mul_by_b_c0 = mnt4_G1::coeff_b * mnt4_Fq2::non_residue.squared(); + mnt4_twist_mul_by_b_c1 = mnt4_G1::coeff_b * mnt4_Fq2::non_residue; + mnt4_twist_mul_by_q_X = mnt4_Fq("475922286169261325753349249653048451545124879242694725395555128576210262817955800483758080"); + mnt4_twist_mul_by_q_Y = mnt4_Fq("7684163245453501615621351552473337069301082060976805004625011694147890954040864167002308"); + + /* choice of group G1 */ + mnt4_G1::G1_zero = mnt4_G1(mnt4_Fq::zero(), + mnt4_Fq::one(), + mnt4_Fq::zero()); + + + mnt4_G1::G1_one = mnt4_G1(mnt4_Fq("60760244141852568949126569781626075788424196370144486719385562369396875346601926534016838"), + mnt4_Fq("363732850702582978263902770815145784459747722357071843971107674179038674942891694705904306"), + mnt4_Fq::one()); + + mnt4_G1::wnaf_window_table.resize(0); + mnt4_G1::wnaf_window_table.push_back(11); + mnt4_G1::wnaf_window_table.push_back(24); + mnt4_G1::wnaf_window_table.push_back(60); + mnt4_G1::wnaf_window_table.push_back(127); + + mnt4_G1::fixed_base_exp_window_table.resize(0); + // window 1 is unbeaten in [-inf, 5.09] + mnt4_G1::fixed_base_exp_window_table.push_back(1); + // window 2 is unbeaten in [5.09, 9.64] + mnt4_G1::fixed_base_exp_window_table.push_back(5); + // window 3 is unbeaten in [9.64, 24.79] + mnt4_G1::fixed_base_exp_window_table.push_back(10); + // window 4 is unbeaten in [24.79, 60.29] + mnt4_G1::fixed_base_exp_window_table.push_back(25); + // window 5 is unbeaten in [60.29, 144.37] + mnt4_G1::fixed_base_exp_window_table.push_back(60); + // window 6 is unbeaten in [144.37, 344.90] + mnt4_G1::fixed_base_exp_window_table.push_back(144); + // window 7 is unbeaten in [344.90, 855.00] + mnt4_G1::fixed_base_exp_window_table.push_back(345); + // window 8 is unbeaten in [855.00, 1804.62] + mnt4_G1::fixed_base_exp_window_table.push_back(855); + // window 9 is unbeaten in [1804.62, 3912.30] + mnt4_G1::fixed_base_exp_window_table.push_back(1805); + // window 10 is unbeaten in [3912.30, 11264.50] + mnt4_G1::fixed_base_exp_window_table.push_back(3912); + // window 11 is unbeaten in [11264.50, 27897.51] + mnt4_G1::fixed_base_exp_window_table.push_back(11265); + // window 12 is unbeaten in [27897.51, 57596.79] + mnt4_G1::fixed_base_exp_window_table.push_back(27898); + // window 13 is unbeaten in [57596.79, 145298.71] + mnt4_G1::fixed_base_exp_window_table.push_back(57597); + // window 14 is unbeaten in [145298.71, 157204.59] + mnt4_G1::fixed_base_exp_window_table.push_back(145299); + // window 15 is unbeaten in [157204.59, 601600.62] + mnt4_G1::fixed_base_exp_window_table.push_back(157205); + // window 16 is unbeaten in [601600.62, 1107377.25] + mnt4_G1::fixed_base_exp_window_table.push_back(601601); + // window 17 is unbeaten in [1107377.25, 1789646.95] + mnt4_G1::fixed_base_exp_window_table.push_back(1107377); + // window 18 is unbeaten in [1789646.95, 4392626.92] + mnt4_G1::fixed_base_exp_window_table.push_back(1789647); + // window 19 is unbeaten in [4392626.92, 8221210.60] + mnt4_G1::fixed_base_exp_window_table.push_back(4392627); + // window 20 is unbeaten in [8221210.60, 42363731.19] + mnt4_G1::fixed_base_exp_window_table.push_back(8221211); + // window 21 is never the best + mnt4_G1::fixed_base_exp_window_table.push_back(0); + // window 22 is unbeaten in [42363731.19, inf] + mnt4_G1::fixed_base_exp_window_table.push_back(42363731); + + /* choice of group G2 */ + mnt4_G2::G2_zero = mnt4_G2(mnt4_Fq2::zero(), + mnt4_Fq2::one(), + mnt4_Fq2::zero()); + + mnt4_G2::G2_one = mnt4_G2(mnt4_Fq2(mnt4_Fq("438374926219350099854919100077809681842783509163790991847867546339851681564223481322252708"), + mnt4_Fq("37620953615500480110935514360923278605464476459712393277679280819942849043649216370485641")), + mnt4_Fq2(mnt4_Fq("37437409008528968268352521034936931842973546441370663118543015118291998305624025037512482"), + mnt4_Fq("424621479598893882672393190337420680597584695892317197646113820787463109735345923009077489")), + mnt4_Fq2::one()); + + mnt4_G2::wnaf_window_table.resize(0); + mnt4_G2::wnaf_window_table.push_back(5); + mnt4_G2::wnaf_window_table.push_back(15); + mnt4_G2::wnaf_window_table.push_back(39); + mnt4_G2::wnaf_window_table.push_back(109); + + mnt4_G2::fixed_base_exp_window_table.resize(0); + // window 1 is unbeaten in [-inf, 4.17] + mnt4_G2::fixed_base_exp_window_table.push_back(1); + // window 2 is unbeaten in [4.17, 10.12] + mnt4_G2::fixed_base_exp_window_table.push_back(4); + // window 3 is unbeaten in [10.12, 24.65] + mnt4_G2::fixed_base_exp_window_table.push_back(10); + // window 4 is unbeaten in [24.65, 60.03] + mnt4_G2::fixed_base_exp_window_table.push_back(25); + // window 5 is unbeaten in [60.03, 143.16] + mnt4_G2::fixed_base_exp_window_table.push_back(60); + // window 6 is unbeaten in [143.16, 344.73] + mnt4_G2::fixed_base_exp_window_table.push_back(143); + // window 7 is unbeaten in [344.73, 821.24] + mnt4_G2::fixed_base_exp_window_table.push_back(345); + // window 8 is unbeaten in [821.24, 1793.92] + mnt4_G2::fixed_base_exp_window_table.push_back(821); + // window 9 is unbeaten in [1793.92, 3919.59] + mnt4_G2::fixed_base_exp_window_table.push_back(1794); + // window 10 is unbeaten in [3919.59, 11301.46] + mnt4_G2::fixed_base_exp_window_table.push_back(3920); + // window 11 is unbeaten in [11301.46, 18960.09] + mnt4_G2::fixed_base_exp_window_table.push_back(11301); + // window 12 is unbeaten in [18960.09, 44198.62] + mnt4_G2::fixed_base_exp_window_table.push_back(18960); + // window 13 is unbeaten in [44198.62, 150799.57] + mnt4_G2::fixed_base_exp_window_table.push_back(44199); + // window 14 is never the best + mnt4_G2::fixed_base_exp_window_table.push_back(0); + // window 15 is unbeaten in [150799.57, 548694.81] + mnt4_G2::fixed_base_exp_window_table.push_back(150800); + // window 16 is unbeaten in [548694.81, 1051769.08] + mnt4_G2::fixed_base_exp_window_table.push_back(548695); + // window 17 is unbeaten in [1051769.08, 2023925.59] + mnt4_G2::fixed_base_exp_window_table.push_back(1051769); + // window 18 is unbeaten in [2023925.59, 3787108.68] + mnt4_G2::fixed_base_exp_window_table.push_back(2023926); + // window 19 is unbeaten in [3787108.68, 7107480.30] + mnt4_G2::fixed_base_exp_window_table.push_back(3787109); + // window 20 is unbeaten in [7107480.30, 38760027.14] + mnt4_G2::fixed_base_exp_window_table.push_back(7107480); + // window 21 is never the best + mnt4_G2::fixed_base_exp_window_table.push_back(0); + // window 22 is unbeaten in [38760027.14, inf] + mnt4_G2::fixed_base_exp_window_table.push_back(38760027); + + /* pairing parameters */ + mnt4_ate_loop_count = bigint_q("689871209842287392837045615510547309923794944"); + mnt4_ate_is_loop_count_neg = false; + mnt4_final_exponent = bigint<4*mnt4_q_limbs>("107797360357109903430794490309592072278927783803031854357910908121903439838772861497177116410825586743089760869945394610511917274977971559062689561855016270594656570874331111995170645233717143416875749097203441437192367065467706065411650403684877366879441766585988546560"); + mnt4_final_exponent_last_chunk_abs_of_w0 = bigint_q("689871209842287392837045615510547309923794945"); + mnt4_final_exponent_last_chunk_is_w0_neg = false; + mnt4_final_exponent_last_chunk_w1 = bigint_q("1"); +} + +} // libsnark diff --git a/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/mnt/mnt4/mnt4_init.hpp b/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/mnt/mnt4/mnt4_init.hpp new file mode 100644 index 0000000..79f449a --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/mnt/mnt4/mnt4_init.hpp @@ -0,0 +1,67 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for initializing MNT4. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef MNT4_INIT_HPP_ +#define MNT4_INIT_HPP_ + +#include "algebra/curves/public_params.hpp" +#include "algebra/curves/mnt/mnt46_common.hpp" +#include "algebra/fields/fp.hpp" +#include "algebra/fields/fp2.hpp" +#include "algebra/fields/fp4.hpp" + +namespace libsnark { + +#define mnt4_modulus_r mnt46_modulus_A +#define mnt4_modulus_q mnt46_modulus_B + +const mp_size_t mnt4_r_bitcount = mnt46_A_bitcount; +const mp_size_t mnt4_q_bitcount = mnt46_B_bitcount; + +const mp_size_t mnt4_r_limbs = mnt46_A_limbs; +const mp_size_t mnt4_q_limbs = mnt46_B_limbs; + +extern bigint mnt4_modulus_r; +extern bigint mnt4_modulus_q; + +typedef Fp_model mnt4_Fr; +typedef Fp_model mnt4_Fq; +typedef Fp2_model mnt4_Fq2; +typedef Fp4_model mnt4_Fq4; +typedef mnt4_Fq4 mnt4_GT; + +// parameters for twisted short Weierstrass curve E'/Fq2 : y^2 = x^3 + (a * twist^2) * x + (b * twist^3) +extern mnt4_Fq2 mnt4_twist; +extern mnt4_Fq2 mnt4_twist_coeff_a; +extern mnt4_Fq2 mnt4_twist_coeff_b; +extern mnt4_Fq mnt4_twist_mul_by_a_c0; +extern mnt4_Fq mnt4_twist_mul_by_a_c1; +extern mnt4_Fq mnt4_twist_mul_by_b_c0; +extern mnt4_Fq mnt4_twist_mul_by_b_c1; +extern mnt4_Fq mnt4_twist_mul_by_q_X; +extern mnt4_Fq mnt4_twist_mul_by_q_Y; + +// parameters for pairing +extern bigint mnt4_ate_loop_count; +extern bool mnt4_ate_is_loop_count_neg; +extern bigint<4*mnt4_q_limbs> mnt4_final_exponent; +extern bigint mnt4_final_exponent_last_chunk_abs_of_w0; +extern bool mnt4_final_exponent_last_chunk_is_w0_neg; +extern bigint mnt4_final_exponent_last_chunk_w1; + +void init_mnt4_params(); + +class mnt4_G1; +class mnt4_G2; + +} // libsnark + +#endif // MNT4_INIT_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/mnt/mnt4/mnt4_pairing.cpp b/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/mnt/mnt4/mnt4_pairing.cpp new file mode 100644 index 0000000..6334283 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/mnt/mnt4/mnt4_pairing.cpp @@ -0,0 +1,742 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for pairing operations on MNT4. + + See mnt4_pairing.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include + +#include "algebra/curves/mnt/mnt4/mnt4_pairing.hpp" + +#include "algebra/curves/mnt/mnt4/mnt4_init.hpp" +#include "algebra/curves/mnt/mnt4/mnt4_g1.hpp" +#include "algebra/curves/mnt/mnt4/mnt4_g2.hpp" +#include "algebra/scalar_multiplication/wnaf.hpp" +#include "common/profiling.hpp" + +namespace libsnark { + +bool mnt4_ate_G1_precomp::operator==(const mnt4_ate_G1_precomp &other) const +{ + return (this->PX == other.PX && + this->PY == other.PY && + this->PX_twist == other.PX_twist && + this->PY_twist == other.PY_twist); +} + +std::ostream& operator<<(std::ostream &out, const mnt4_ate_G1_precomp &prec_P) +{ + out << prec_P.PX << OUTPUT_SEPARATOR << prec_P.PY << OUTPUT_SEPARATOR << prec_P.PX_twist << OUTPUT_SEPARATOR << prec_P.PY_twist; + + return out; +} + +std::istream& operator>>(std::istream &in, mnt4_ate_G1_precomp &prec_P) +{ + in >> prec_P.PX; + consume_OUTPUT_SEPARATOR(in); + in >> prec_P.PY; + consume_OUTPUT_SEPARATOR(in); + in >> prec_P.PX_twist; + consume_OUTPUT_SEPARATOR(in); + in >> prec_P.PY_twist; + + return in; +} + +bool mnt4_ate_dbl_coeffs::operator==(const mnt4_ate_dbl_coeffs &other) const +{ + return (this->c_H == other.c_H && + this->c_4C == other.c_4C && + this->c_J == other.c_J && + this->c_L == other.c_L); +} + +std::ostream& operator<<(std::ostream &out, const mnt4_ate_dbl_coeffs &dc) +{ + out << dc.c_H << OUTPUT_SEPARATOR << dc.c_4C << OUTPUT_SEPARATOR << dc.c_J << OUTPUT_SEPARATOR << dc.c_L; + return out; +} + +std::istream& operator>>(std::istream &in, mnt4_ate_dbl_coeffs &dc) +{ + in >> dc.c_H; + consume_OUTPUT_SEPARATOR(in); + in >> dc.c_4C; + consume_OUTPUT_SEPARATOR(in); + in >> dc.c_J; + consume_OUTPUT_SEPARATOR(in); + in >> dc.c_L; + + return in; +} + +bool mnt4_ate_add_coeffs::operator==(const mnt4_ate_add_coeffs &other) const +{ + return (this->c_L1 == other.c_L1 && + this->c_RZ == other.c_RZ); +} + +std::ostream& operator<<(std::ostream &out, const mnt4_ate_add_coeffs &ac) +{ + out << ac.c_L1 << OUTPUT_SEPARATOR << ac.c_RZ; + return out; +} + +std::istream& operator>>(std::istream &in, mnt4_ate_add_coeffs &ac) +{ + in >> ac.c_L1; + consume_OUTPUT_SEPARATOR(in); + in >> ac.c_RZ; + return in; +} + +bool mnt4_ate_G2_precomp::operator==(const mnt4_ate_G2_precomp &other) const +{ + return (this->QX == other.QX && + this->QY == other.QY && + this->QY2 == other.QY2 && + this->QX_over_twist == other.QX_over_twist && + this->QY_over_twist == other.QY_over_twist && + this->dbl_coeffs == other.dbl_coeffs && + this->add_coeffs == other.add_coeffs); +} + +std::ostream& operator<<(std::ostream& out, const mnt4_ate_G2_precomp &prec_Q) +{ + out << prec_Q.QX << OUTPUT_SEPARATOR + << prec_Q.QY << OUTPUT_SEPARATOR + << prec_Q.QY2 << OUTPUT_SEPARATOR + << prec_Q.QX_over_twist << OUTPUT_SEPARATOR + << prec_Q.QY_over_twist << "\n"; + out << prec_Q.dbl_coeffs.size() << "\n"; + for (const mnt4_ate_dbl_coeffs &dc : prec_Q.dbl_coeffs) + { + out << dc << OUTPUT_NEWLINE; + } + out << prec_Q.add_coeffs.size() << "\n"; + for (const mnt4_ate_add_coeffs &ac : prec_Q.add_coeffs) + { + out << ac << OUTPUT_NEWLINE; + } + + return out; +} + +std::istream& operator>>(std::istream& in, mnt4_ate_G2_precomp &prec_Q) +{ + in >> prec_Q.QX; + consume_OUTPUT_SEPARATOR(in); + in >> prec_Q.QY; + consume_OUTPUT_SEPARATOR(in); + in >> prec_Q.QY2; + consume_OUTPUT_SEPARATOR(in); + in >> prec_Q.QX_over_twist; + consume_OUTPUT_SEPARATOR(in); + in >> prec_Q.QY_over_twist; + consume_newline(in); + + prec_Q.dbl_coeffs.clear(); + size_t dbl_s; + in >> dbl_s; + consume_newline(in); + + prec_Q.dbl_coeffs.reserve(dbl_s); + + for (size_t i = 0; i < dbl_s; ++i) + { + mnt4_ate_dbl_coeffs dc; + in >> dc; + consume_OUTPUT_NEWLINE(in); + prec_Q.dbl_coeffs.emplace_back(dc); + } + + prec_Q.add_coeffs.clear(); + size_t add_s; + in >> add_s; + consume_newline(in); + + prec_Q.add_coeffs.reserve(add_s); + + for (size_t i = 0; i < add_s; ++i) + { + mnt4_ate_add_coeffs ac; + in >> ac; + consume_OUTPUT_NEWLINE(in); + prec_Q.add_coeffs.emplace_back(ac); + } + + return in; +} + +/* final exponentiations */ + +mnt4_Fq4 mnt4_final_exponentiation_last_chunk(const mnt4_Fq4 &elt, const mnt4_Fq4 &elt_inv) +{ + enter_block("Call to mnt4_final_exponentiation_last_chunk"); + const mnt4_Fq4 elt_q = elt.Frobenius_map(1); + mnt4_Fq4 w1_part = elt_q.cyclotomic_exp(mnt4_final_exponent_last_chunk_w1); + mnt4_Fq4 w0_part; + if (mnt4_final_exponent_last_chunk_is_w0_neg) + { + w0_part = elt_inv.cyclotomic_exp(mnt4_final_exponent_last_chunk_abs_of_w0); + } else { + w0_part = elt.cyclotomic_exp(mnt4_final_exponent_last_chunk_abs_of_w0); + } + mnt4_Fq4 result = w1_part * w0_part; + leave_block("Call to mnt4_final_exponentiation_last_chunk"); + + return result; +} + +mnt4_Fq4 mnt4_final_exponentiation_first_chunk(const mnt4_Fq4 &elt, const mnt4_Fq4 &elt_inv) +{ + enter_block("Call to mnt4_final_exponentiation_first_chunk"); + + /* (q^2-1) */ + + /* elt_q2 = elt^(q^2) */ + const mnt4_Fq4 elt_q2 = elt.Frobenius_map(2); + /* elt_q3_over_elt = elt^(q^2-1) */ + const mnt4_Fq4 elt_q2_over_elt = elt_q2 * elt_inv; + + leave_block("Call to mnt4_final_exponentiation_first_chunk"); + return elt_q2_over_elt; +} + +mnt4_GT mnt4_final_exponentiation(const mnt4_Fq4 &elt) +{ + enter_block("Call to mnt4_final_exponentiation"); + const mnt4_Fq4 elt_inv = elt.inverse(); + const mnt4_Fq4 elt_to_first_chunk = mnt4_final_exponentiation_first_chunk(elt, elt_inv); + const mnt4_Fq4 elt_inv_to_first_chunk = mnt4_final_exponentiation_first_chunk(elt_inv, elt); + mnt4_GT result = mnt4_final_exponentiation_last_chunk(elt_to_first_chunk, elt_inv_to_first_chunk); + leave_block("Call to mnt4_final_exponentiation"); + + return result; +} + +/* affine ate miller loop */ + +mnt4_affine_ate_G1_precomputation mnt4_affine_ate_precompute_G1(const mnt4_G1& P) +{ + enter_block("Call to mnt4_affine_ate_precompute_G1"); + + mnt4_G1 Pcopy = P; + Pcopy.to_affine_coordinates(); + + mnt4_affine_ate_G1_precomputation result; + result.PX = Pcopy.X(); + result.PY = Pcopy.Y(); + result.PY_twist_squared = Pcopy.Y() * mnt4_twist.squared(); + + leave_block("Call to mnt4_affine_ate_precompute_G1"); + return result; +} + +mnt4_affine_ate_G2_precomputation mnt4_affine_ate_precompute_G2(const mnt4_G2& Q) +{ + enter_block("Call to mnt4_affine_ate_precompute_G2"); + + mnt4_G2 Qcopy(Q); + Qcopy.to_affine_coordinates(); + + mnt4_affine_ate_G2_precomputation result; + result.QX = Qcopy.X(); + result.QY = Qcopy.Y(); + + mnt4_Fq2 RX = Qcopy.X(); + mnt4_Fq2 RY = Qcopy.Y(); + + const bigint &loop_count = mnt4_ate_loop_count; + bool found_nonzero = false; + + std::vector NAF = find_wnaf(1, loop_count); + for (long i = NAF.size() - 1; i >= 0; --i) + { + if (!found_nonzero) + { + /* this skips the MSB itself */ + found_nonzero |= (NAF[i] != 0); + continue; + } + + mnt4_affine_ate_coeffs c; + c.old_RX = RX; + c.old_RY = RY; + mnt4_Fq2 old_RX_2 = c.old_RX.squared(); + c.gamma = (old_RX_2 + old_RX_2 + old_RX_2 + mnt4_twist_coeff_a) * (c.old_RY + c.old_RY).inverse(); + c.gamma_twist = c.gamma * mnt4_twist; + c.gamma_X = c.gamma * c.old_RX; + result.coeffs.push_back(c); + + RX = c.gamma.squared() - (c.old_RX+c.old_RX); + RY = c.gamma * (c.old_RX - RX) - c.old_RY; + + if (NAF[i] != 0) + { + mnt4_affine_ate_coeffs c; + c.old_RX = RX; + c.old_RY = RY; + if (NAF[i] > 0) + { + c.gamma = (c.old_RY - result.QY) * (c.old_RX - result.QX).inverse(); + } + else + { + c.gamma = (c.old_RY + result.QY) * (c.old_RX - result.QX).inverse(); + } + c.gamma_twist = c.gamma * mnt4_twist; + c.gamma_X = c.gamma * result.QX; + result.coeffs.push_back(c); + + RX = c.gamma.squared() - (c.old_RX+result.QX); + RY = c.gamma * (c.old_RX - RX) - c.old_RY; + } + } + + /* TODO: maybe handle neg + if (mnt4_ate_is_loop_count_neg) + { + mnt4_ate_add_coeffs ac; + mnt4_affine_ate_dbl_coeffs c; + c.old_RX = RX; + c.old_RY = -RY; + old_RX_2 = c.old_RY.squared(); + c.gamma = (old_RX_2 + old_RX_2 + old_RX_2 + mnt4_coeff_a) * (c.old_RY + c.old_RY).inverse(); + c.gamma_twist = c.gamma * mnt4_twist; + c.gamma_X = c.gamma * c.old_RX; + result.coeffs.push_back(c); + } + */ + + leave_block("Call to mnt4_affine_ate_precompute_G2"); + return result; +} + +mnt4_Fq4 mnt4_affine_ate_miller_loop(const mnt4_affine_ate_G1_precomputation &prec_P, + const mnt4_affine_ate_G2_precomputation &prec_Q) +{ + enter_block("Call to mnt4_affine_ate_miller_loop"); + + mnt4_Fq4 f = mnt4_Fq4::one(); + + bool found_nonzero = false; + size_t idx = 0; + const bigint &loop_count = mnt4_ate_loop_count; + + std::vector NAF = find_wnaf(1, loop_count); + for (long i = NAF.size() - 1; i >= 0; --i) + { + if (!found_nonzero) + { + /* this skips the MSB itself */ + found_nonzero |= (NAF[i] != 0); + continue; + } + + /* code below gets executed for all bits (EXCEPT the MSB itself) of + mnt4_param_p (skipping leading zeros) in MSB to LSB + order */ + mnt4_affine_ate_coeffs c = prec_Q.coeffs[idx++]; + + mnt4_Fq4 g_RR_at_P = mnt4_Fq4(prec_P.PY_twist_squared, + - prec_P.PX * c.gamma_twist + c.gamma_X - c.old_RY); + f = f.squared().mul_by_023(g_RR_at_P); + + if (NAF[i] != 0) + { + mnt4_affine_ate_coeffs c = prec_Q.coeffs[idx++]; + mnt4_Fq4 g_RQ_at_P; + if (NAF[i] > 0) + { + g_RQ_at_P = mnt4_Fq4(prec_P.PY_twist_squared, + - prec_P.PX * c.gamma_twist + c.gamma_X - prec_Q.QY); + } + else + { + g_RQ_at_P = mnt4_Fq4(prec_P.PY_twist_squared, + - prec_P.PX * c.gamma_twist + c.gamma_X + prec_Q.QY); + } + f = f.mul_by_023(g_RQ_at_P); + } + } + + /* TODO: maybe handle neg + if (mnt4_ate_is_loop_count_neg) + { + // TODO: + mnt4_affine_ate_coeffs ac = prec_Q.coeffs[idx++]; + mnt4_Fq4 g_RnegR_at_P = mnt4_Fq4(prec_P.PY_twist_squared, + - prec_P.PX * c.gamma_twist + c.gamma_X - c.old_RY); + f = (f * g_RnegR_at_P).inverse(); + } + */ + + leave_block("Call to mnt4_affine_ate_miller_loop"); + + return f; +} + +/* ate pairing */ + +struct extended_mnt4_G2_projective { + mnt4_Fq2 X; + mnt4_Fq2 Y; + mnt4_Fq2 Z; + mnt4_Fq2 T; + + void print() const + { + printf("extended mnt4_G2 projective X/Y/Z/T:\n"); + X.print(); + Y.print(); + Z.print(); + T.print(); + } + + void test_invariant() const + { + assert(T == Z.squared()); + } +}; + +void doubling_step_for_flipped_miller_loop(extended_mnt4_G2_projective ¤t, + mnt4_ate_dbl_coeffs &dc) +{ + const mnt4_Fq2 X = current.X, Y = current.Y, Z = current.Z, T = current.T; + + const mnt4_Fq2 A = T.squared(); // A = T1^2 + const mnt4_Fq2 B = X.squared(); // B = X1^2 + const mnt4_Fq2 C = Y.squared(); // C = Y1^2 + const mnt4_Fq2 D = C.squared(); // D = C^2 + const mnt4_Fq2 E = (X+C).squared() - B - D; // E = (X1+C)^2-B-D + const mnt4_Fq2 F = (B+B+B) + mnt4_twist_coeff_a * A; // F = 3*B + a *A + const mnt4_Fq2 G = F.squared(); // G = F^2 + + current.X = -(E+E+E+E) + G; // X3 = -4*E+G + current.Y = -mnt4_Fq("8")*D + F*(E+E-current.X); // Y3 = -8*D+F*(2*E-X3) + current.Z = (Y+Z).squared() - C - Z.squared(); // Z3 = (Y1+Z1)^2-C-Z1^2 + current.T = current.Z.squared(); // T3 = Z3^2 + + dc.c_H = (current.Z + T).squared() - current.T - A; // H = (Z3+T1)^2-T3-A + dc.c_4C = C+C+C+C; // fourC = 4*C + dc.c_J = (F+T).squared() - G - A; // J = (F+T1)^2-G-A + dc.c_L = (F+X).squared() - G - B; // L = (F+X1)^2-G-B + +#ifdef DEBUG + current.test_invariant(); +#endif +} + +void mixed_addition_step_for_flipped_miller_loop(const mnt4_Fq2 base_X, const mnt4_Fq2 base_Y, const mnt4_Fq2 base_Y_squared, + extended_mnt4_G2_projective ¤t, + mnt4_ate_add_coeffs &ac) +{ + const mnt4_Fq2 X1 = current.X, Y1 = current.Y, Z1 = current.Z, T1 = current.T; + const mnt4_Fq2 &x2 = base_X, &y2 = base_Y, &y2_squared = base_Y_squared; + + const mnt4_Fq2 B = x2 * T1; // B = x2 * T1 + const mnt4_Fq2 D = ((y2 + Z1).squared() - y2_squared - T1) * T1; // D = ((y2 + Z1)^2 - y2squared - T1) * T1 + const mnt4_Fq2 H = B - X1; // H = B - X1 + const mnt4_Fq2 I = H.squared(); // I = H^2 + const mnt4_Fq2 E = I + I + I + I; // E = 4*I + const mnt4_Fq2 J = H * E; // J = H * E + const mnt4_Fq2 V = X1 * E; // V = X1 * E + const mnt4_Fq2 L1 = D - (Y1 + Y1); // L1 = D - 2 * Y1 + + current.X = L1.squared() - J - (V+V); // X3 = L1^2 - J - 2*V + current.Y = L1 * (V-current.X) - (Y1+Y1) * J; // Y3 = L1 * (V-X3) - 2*Y1 * J + current.Z = (Z1+H).squared() - T1 - I; // Z3 = (Z1 + H)^2 - T1 - I + current.T = current.Z.squared(); // T3 = Z3^2 + + ac.c_L1 = L1; + ac.c_RZ = current.Z; +#ifdef DEBUG + current.test_invariant(); +#endif +} + +mnt4_ate_G1_precomp mnt4_ate_precompute_G1(const mnt4_G1& P) +{ + enter_block("Call to mnt4_ate_precompute_G1"); + + mnt4_G1 Pcopy = P; + Pcopy.to_affine_coordinates(); + + mnt4_ate_G1_precomp result; + result.PX = Pcopy.X(); + result.PY = Pcopy.Y(); + result.PX_twist = Pcopy.X() * mnt4_twist; + result.PY_twist = Pcopy.Y() * mnt4_twist; + + leave_block("Call to mnt4_ate_precompute_G1"); + return result; +} + +mnt4_ate_G2_precomp mnt4_ate_precompute_G2(const mnt4_G2& Q) +{ + enter_block("Call to mnt4_ate_precompute_G2"); + + mnt4_G2 Qcopy(Q); + Qcopy.to_affine_coordinates(); + + mnt4_ate_G2_precomp result; + result.QX = Qcopy.X(); + result.QY = Qcopy.Y(); + result.QY2 = Qcopy.Y().squared(); + result.QX_over_twist = Qcopy.X() * mnt4_twist.inverse(); + result.QY_over_twist = Qcopy.Y() * mnt4_twist.inverse(); + + extended_mnt4_G2_projective R; + R.X = Qcopy.X(); + R.Y = Qcopy.Y(); + R.Z = mnt4_Fq2::one(); + R.T = mnt4_Fq2::one(); + + const bigint &loop_count = mnt4_ate_loop_count; + bool found_one = false; + + for (long i = loop_count.max_bits() - 1; i >= 0; --i) + { + const bool bit = loop_count.test_bit(i); + if (!found_one) + { + /* this skips the MSB itself */ + found_one |= bit; + continue; + } + + mnt4_ate_dbl_coeffs dc; + doubling_step_for_flipped_miller_loop(R, dc); + result.dbl_coeffs.push_back(dc); + if (bit) + { + mnt4_ate_add_coeffs ac; + mixed_addition_step_for_flipped_miller_loop(result.QX, result.QY, result.QY2, R, ac); + result.add_coeffs.push_back(ac); + } + } + + if (mnt4_ate_is_loop_count_neg) + { + mnt4_Fq2 RZ_inv = R.Z.inverse(); + mnt4_Fq2 RZ2_inv = RZ_inv.squared(); + mnt4_Fq2 RZ3_inv = RZ2_inv * RZ_inv; + mnt4_Fq2 minus_R_affine_X = R.X * RZ2_inv; + mnt4_Fq2 minus_R_affine_Y = - R.Y * RZ3_inv; + mnt4_Fq2 minus_R_affine_Y2 = minus_R_affine_Y.squared(); + mnt4_ate_add_coeffs ac; + mixed_addition_step_for_flipped_miller_loop(minus_R_affine_X, minus_R_affine_Y, minus_R_affine_Y2, R, ac); + result.add_coeffs.push_back(ac); + } + + leave_block("Call to mnt4_ate_precompute_G2"); + return result; +} + +mnt4_Fq4 mnt4_ate_miller_loop(const mnt4_ate_G1_precomp &prec_P, + const mnt4_ate_G2_precomp &prec_Q) +{ + enter_block("Call to mnt4_ate_miller_loop"); + + mnt4_Fq2 L1_coeff = mnt4_Fq2(prec_P.PX, mnt4_Fq::zero()) - prec_Q.QX_over_twist; + + mnt4_Fq4 f = mnt4_Fq4::one(); + + bool found_one = false; + size_t dbl_idx = 0; + size_t add_idx = 0; + + const bigint &loop_count = mnt4_ate_loop_count; + for (long i = loop_count.max_bits() - 1; i >= 0; --i) + { + const bool bit = loop_count.test_bit(i); + + if (!found_one) + { + /* this skips the MSB itself */ + found_one |= bit; + continue; + } + + /* code below gets executed for all bits (EXCEPT the MSB itself) of + mnt4_param_p (skipping leading zeros) in MSB to LSB + order */ + mnt4_ate_dbl_coeffs dc = prec_Q.dbl_coeffs[dbl_idx++]; + + mnt4_Fq4 g_RR_at_P = mnt4_Fq4(- dc.c_4C - dc.c_J * prec_P.PX_twist + dc.c_L, + dc.c_H * prec_P.PY_twist); + f = f.squared() * g_RR_at_P; + if (bit) + { + mnt4_ate_add_coeffs ac = prec_Q.add_coeffs[add_idx++]; + + mnt4_Fq4 g_RQ_at_P = mnt4_Fq4(ac.c_RZ * prec_P.PY_twist, + -(prec_Q.QY_over_twist * ac.c_RZ + L1_coeff * ac.c_L1)); + f = f * g_RQ_at_P; + } + } + + if (mnt4_ate_is_loop_count_neg) + { + mnt4_ate_add_coeffs ac = prec_Q.add_coeffs[add_idx++]; + mnt4_Fq4 g_RnegR_at_P = mnt4_Fq4(ac.c_RZ * prec_P.PY_twist, + -(prec_Q.QY_over_twist * ac.c_RZ + L1_coeff * ac.c_L1)); + f = (f * g_RnegR_at_P).inverse(); + } + + leave_block("Call to mnt4_ate_miller_loop"); + + return f; +} + +mnt4_Fq4 mnt4_ate_double_miller_loop(const mnt4_ate_G1_precomp &prec_P1, + const mnt4_ate_G2_precomp &prec_Q1, + const mnt4_ate_G1_precomp &prec_P2, + const mnt4_ate_G2_precomp &prec_Q2) +{ + enter_block("Call to mnt4_ate_double_miller_loop"); + + mnt4_Fq2 L1_coeff1 = mnt4_Fq2(prec_P1.PX, mnt4_Fq::zero()) - prec_Q1.QX_over_twist; + mnt4_Fq2 L1_coeff2 = mnt4_Fq2(prec_P2.PX, mnt4_Fq::zero()) - prec_Q2.QX_over_twist; + + mnt4_Fq4 f = mnt4_Fq4::one(); + + bool found_one = false; + size_t dbl_idx = 0; + size_t add_idx = 0; + + const bigint &loop_count = mnt4_ate_loop_count; + for (long i = loop_count.max_bits() - 1; i >= 0; --i) + { + const bool bit = loop_count.test_bit(i); + + if (!found_one) + { + /* this skips the MSB itself */ + found_one |= bit; + continue; + } + + /* code below gets executed for all bits (EXCEPT the MSB itself) of + mnt4_param_p (skipping leading zeros) in MSB to LSB + order */ + mnt4_ate_dbl_coeffs dc1 = prec_Q1.dbl_coeffs[dbl_idx]; + mnt4_ate_dbl_coeffs dc2 = prec_Q2.dbl_coeffs[dbl_idx]; + ++dbl_idx; + + mnt4_Fq4 g_RR_at_P1 = mnt4_Fq4(- dc1.c_4C - dc1.c_J * prec_P1.PX_twist + dc1.c_L, + dc1.c_H * prec_P1.PY_twist); + + mnt4_Fq4 g_RR_at_P2 = mnt4_Fq4(- dc2.c_4C - dc2.c_J * prec_P2.PX_twist + dc2.c_L, + dc2.c_H * prec_P2.PY_twist); + + f = f.squared() * g_RR_at_P1 * g_RR_at_P2; + + if (bit) + { + mnt4_ate_add_coeffs ac1 = prec_Q1.add_coeffs[add_idx]; + mnt4_ate_add_coeffs ac2 = prec_Q2.add_coeffs[add_idx]; + ++add_idx; + + mnt4_Fq4 g_RQ_at_P1 = mnt4_Fq4(ac1.c_RZ * prec_P1.PY_twist, + -(prec_Q1.QY_over_twist * ac1.c_RZ + L1_coeff1 * ac1.c_L1)); + mnt4_Fq4 g_RQ_at_P2 = mnt4_Fq4(ac2.c_RZ * prec_P2.PY_twist, + -(prec_Q2.QY_over_twist * ac2.c_RZ + L1_coeff2 * ac2.c_L1)); + + f = f * g_RQ_at_P1 * g_RQ_at_P2; + } + } + + if (mnt4_ate_is_loop_count_neg) + { + mnt4_ate_add_coeffs ac1 = prec_Q1.add_coeffs[add_idx]; + mnt4_ate_add_coeffs ac2 = prec_Q2.add_coeffs[add_idx]; + ++add_idx; + mnt4_Fq4 g_RnegR_at_P1 = mnt4_Fq4(ac1.c_RZ * prec_P1.PY_twist, + -(prec_Q1.QY_over_twist * ac1.c_RZ + L1_coeff1 * ac1.c_L1)); + mnt4_Fq4 g_RnegR_at_P2 = mnt4_Fq4(ac2.c_RZ * prec_P2.PY_twist, + -(prec_Q2.QY_over_twist * ac2.c_RZ + L1_coeff2 * ac2.c_L1)); + + f = (f * g_RnegR_at_P1 * g_RnegR_at_P2).inverse(); + } + + leave_block("Call to mnt4_ate_double_miller_loop"); + + return f; +} + +mnt4_Fq4 mnt4_ate_pairing(const mnt4_G1& P, const mnt4_G2 &Q) +{ + enter_block("Call to mnt4_ate_pairing"); + mnt4_ate_G1_precomp prec_P = mnt4_ate_precompute_G1(P); + mnt4_ate_G2_precomp prec_Q = mnt4_ate_precompute_G2(Q); + mnt4_Fq4 result = mnt4_ate_miller_loop(prec_P, prec_Q); + leave_block("Call to mnt4_ate_pairing"); + return result; +} + +mnt4_GT mnt4_ate_reduced_pairing(const mnt4_G1 &P, const mnt4_G2 &Q) +{ + enter_block("Call to mnt4_ate_reduced_pairing"); + const mnt4_Fq4 f = mnt4_ate_pairing(P, Q); + const mnt4_GT result = mnt4_final_exponentiation(f); + leave_block("Call to mnt4_ate_reduced_pairing"); + return result; +} + +mnt4_G1_precomp mnt4_precompute_G1(const mnt4_G1& P) +{ + return mnt4_ate_precompute_G1(P); +} + +mnt4_G2_precomp mnt4_precompute_G2(const mnt4_G2& Q) +{ + return mnt4_ate_precompute_G2(Q); +} + +mnt4_Fq4 mnt4_miller_loop(const mnt4_G1_precomp &prec_P, + const mnt4_G2_precomp &prec_Q) +{ + return mnt4_ate_miller_loop(prec_P, prec_Q); +} + +mnt4_Fq4 mnt4_double_miller_loop(const mnt4_G1_precomp &prec_P1, + const mnt4_G2_precomp &prec_Q1, + const mnt4_G1_precomp &prec_P2, + const mnt4_G2_precomp &prec_Q2) +{ + return mnt4_ate_double_miller_loop(prec_P1, prec_Q1, prec_P2, prec_Q2); +} + +mnt4_Fq4 mnt4_pairing(const mnt4_G1& P, + const mnt4_G2 &Q) +{ + return mnt4_ate_pairing(P, Q); +} + +mnt4_GT mnt4_reduced_pairing(const mnt4_G1 &P, + const mnt4_G2 &Q) +{ + return mnt4_ate_reduced_pairing(P, Q); +} + +mnt4_GT mnt4_affine_reduced_pairing(const mnt4_G1 &P, + const mnt4_G2 &Q) +{ + const mnt4_affine_ate_G1_precomputation prec_P = mnt4_affine_ate_precompute_G1(P); + const mnt4_affine_ate_G2_precomputation prec_Q = mnt4_affine_ate_precompute_G2(Q); + const mnt4_Fq4 f = mnt4_affine_ate_miller_loop(prec_P, prec_Q); + const mnt4_GT result = mnt4_final_exponentiation(f); + return result; +} + +} // libsnark diff --git a/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/mnt/mnt4/mnt4_pairing.hpp b/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/mnt/mnt4/mnt4_pairing.hpp new file mode 100644 index 0000000..0047115 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/mnt/mnt4/mnt4_pairing.hpp @@ -0,0 +1,148 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for pairing operations on MNT4. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef MNT4_PAIRING_HPP_ +#define MNT4_PAIRING_HPP_ + +#include + +#include "algebra/curves/mnt/mnt4/mnt4_init.hpp" + +namespace libsnark { + +/* final exponentiation */ + +mnt4_Fq4 mnt4_final_exponentiation_last_chunk(const mnt4_Fq4 &elt, + const mnt4_Fq4 &elt_inv); +mnt4_Fq4 mnt4_final_exponentiation_first_chunk(const mnt4_Fq4 &elt, + const mnt4_Fq4 &elt_inv); +mnt4_GT mnt4_final_exponentiation(const mnt4_Fq4 &elt); + +/* affine ate miller loop */ + +struct mnt4_affine_ate_G1_precomputation { + mnt4_Fq PX; + mnt4_Fq PY; + mnt4_Fq2 PY_twist_squared; +}; + +struct mnt4_affine_ate_coeffs { + // TODO: trim (not all of them are needed) + mnt4_Fq2 old_RX; + mnt4_Fq2 old_RY; + mnt4_Fq2 gamma; + mnt4_Fq2 gamma_twist; + mnt4_Fq2 gamma_X; +}; + +struct mnt4_affine_ate_G2_precomputation { + mnt4_Fq2 QX; + mnt4_Fq2 QY; + std::vector coeffs; +}; + +mnt4_affine_ate_G1_precomputation mnt4_affine_ate_precompute_G1(const mnt4_G1& P); +mnt4_affine_ate_G2_precomputation mnt4_affine_ate_precompute_G2(const mnt4_G2& Q); + +mnt4_Fq4 mnt4_affine_ate_miller_loop(const mnt4_affine_ate_G1_precomputation &prec_P, + const mnt4_affine_ate_G2_precomputation &prec_Q); + +/* ate pairing */ + +struct mnt4_ate_G1_precomp { + mnt4_Fq PX; + mnt4_Fq PY; + mnt4_Fq2 PX_twist; + mnt4_Fq2 PY_twist; + + bool operator==(const mnt4_ate_G1_precomp &other) const; + friend std::ostream& operator<<(std::ostream &out, const mnt4_ate_G1_precomp &prec_P); + friend std::istream& operator>>(std::istream &in, mnt4_ate_G1_precomp &prec_P); +}; + +struct mnt4_ate_dbl_coeffs { + mnt4_Fq2 c_H; + mnt4_Fq2 c_4C; + mnt4_Fq2 c_J; + mnt4_Fq2 c_L; + + bool operator==(const mnt4_ate_dbl_coeffs &other) const; + friend std::ostream& operator<<(std::ostream &out, const mnt4_ate_dbl_coeffs &dc); + friend std::istream& operator>>(std::istream &in, mnt4_ate_dbl_coeffs &dc); +}; + +struct mnt4_ate_add_coeffs { + mnt4_Fq2 c_L1; + mnt4_Fq2 c_RZ; + + bool operator==(const mnt4_ate_add_coeffs &other) const; + friend std::ostream& operator<<(std::ostream &out, const mnt4_ate_add_coeffs &dc); + friend std::istream& operator>>(std::istream &in, mnt4_ate_add_coeffs &dc); +}; + +struct mnt4_ate_G2_precomp { + mnt4_Fq2 QX; + mnt4_Fq2 QY; + mnt4_Fq2 QY2; + mnt4_Fq2 QX_over_twist; + mnt4_Fq2 QY_over_twist; + std::vector dbl_coeffs; + std::vector add_coeffs; + + bool operator==(const mnt4_ate_G2_precomp &other) const; + friend std::ostream& operator<<(std::ostream &out, const mnt4_ate_G2_precomp &prec_Q); + friend std::istream& operator>>(std::istream &in, mnt4_ate_G2_precomp &prec_Q); +}; + +mnt4_ate_G1_precomp mnt4_ate_precompute_G1(const mnt4_G1& P); +mnt4_ate_G2_precomp mnt4_ate_precompute_G2(const mnt4_G2& Q); + +mnt4_Fq4 mnt4_ate_miller_loop(const mnt4_ate_G1_precomp &prec_P, + const mnt4_ate_G2_precomp &prec_Q); +mnt4_Fq4 mnt4_ate_double_miller_loop(const mnt4_ate_G1_precomp &prec_P1, + const mnt4_ate_G2_precomp &prec_Q1, + const mnt4_ate_G1_precomp &prec_P2, + const mnt4_ate_G2_precomp &prec_Q2); + +mnt4_Fq4 mnt4_ate_pairing(const mnt4_G1& P, + const mnt4_G2 &Q); +mnt4_GT mnt4_ate_reduced_pairing(const mnt4_G1 &P, + const mnt4_G2 &Q); + +/* choice of pairing */ + +typedef mnt4_ate_G1_precomp mnt4_G1_precomp; +typedef mnt4_ate_G2_precomp mnt4_G2_precomp; + +mnt4_G1_precomp mnt4_precompute_G1(const mnt4_G1& P); + +mnt4_G2_precomp mnt4_precompute_G2(const mnt4_G2& Q); + +mnt4_Fq4 mnt4_miller_loop(const mnt4_G1_precomp &prec_P, + const mnt4_G2_precomp &prec_Q); + +mnt4_Fq4 mnt4_double_miller_loop(const mnt4_G1_precomp &prec_P1, + const mnt4_G2_precomp &prec_Q1, + const mnt4_G1_precomp &prec_P2, + const mnt4_G2_precomp &prec_Q2); + +mnt4_Fq4 mnt4_pairing(const mnt4_G1& P, + const mnt4_G2 &Q); + +mnt4_GT mnt4_reduced_pairing(const mnt4_G1 &P, + const mnt4_G2 &Q); + +mnt4_GT mnt4_affine_reduced_pairing(const mnt4_G1 &P, + const mnt4_G2 &Q); + +} // libsnark + +#endif // MNT4_PAIRING_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/mnt/mnt4/mnt4_pp.cpp b/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/mnt/mnt4/mnt4_pp.cpp new file mode 100644 index 0000000..17eccab --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/mnt/mnt4/mnt4_pp.cpp @@ -0,0 +1,105 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for public parameters of MNT4. + + See mnt4_pp.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include "algebra/curves/mnt/mnt4/mnt4_pp.hpp" + +namespace libsnark { + +void mnt4_pp::init_public_params() +{ + init_mnt4_params(); +} + +mnt4_GT mnt4_pp::final_exponentiation(const mnt4_Fq4 &elt) +{ + return mnt4_final_exponentiation(elt); +} + +mnt4_G1_precomp mnt4_pp::precompute_G1(const mnt4_G1 &P) +{ + return mnt4_precompute_G1(P); +} + +mnt4_G2_precomp mnt4_pp::precompute_G2(const mnt4_G2 &Q) +{ + return mnt4_precompute_G2(Q); +} + +mnt4_Fq4 mnt4_pp::miller_loop(const mnt4_G1_precomp &prec_P, + const mnt4_G2_precomp &prec_Q) +{ + return mnt4_miller_loop(prec_P, prec_Q); +} + +mnt4_affine_ate_G1_precomputation mnt4_pp::affine_ate_precompute_G1(const mnt4_G1 &P) +{ + return mnt4_affine_ate_precompute_G1(P); +} + +mnt4_affine_ate_G2_precomputation mnt4_pp::affine_ate_precompute_G2(const mnt4_G2 &Q) +{ + return mnt4_affine_ate_precompute_G2(Q); +} + +mnt4_Fq4 mnt4_pp::affine_ate_miller_loop(const mnt4_affine_ate_G1_precomputation &prec_P, + const mnt4_affine_ate_G2_precomputation &prec_Q) +{ + return mnt4_affine_ate_miller_loop(prec_P, prec_Q); +} + +mnt4_Fq4 mnt4_pp::affine_ate_e_over_e_miller_loop(const mnt4_affine_ate_G1_precomputation &prec_P1, + const mnt4_affine_ate_G2_precomputation &prec_Q1, + const mnt4_affine_ate_G1_precomputation &prec_P2, + const mnt4_affine_ate_G2_precomputation &prec_Q2) +{ + return mnt4_affine_ate_miller_loop(prec_P1, prec_Q1) * mnt4_affine_ate_miller_loop(prec_P2, prec_Q2).unitary_inverse(); +} + +mnt4_Fq4 mnt4_pp::affine_ate_e_times_e_over_e_miller_loop(const mnt4_affine_ate_G1_precomputation &prec_P1, + const mnt4_affine_ate_G2_precomputation &prec_Q1, + const mnt4_affine_ate_G1_precomputation &prec_P2, + const mnt4_affine_ate_G2_precomputation &prec_Q2, + const mnt4_affine_ate_G1_precomputation &prec_P3, + const mnt4_affine_ate_G2_precomputation &prec_Q3) +{ + return ((mnt4_affine_ate_miller_loop(prec_P1, prec_Q1) * mnt4_affine_ate_miller_loop(prec_P2, prec_Q2)) * + mnt4_affine_ate_miller_loop(prec_P3, prec_Q3).unitary_inverse()); +} + +mnt4_Fq4 mnt4_pp::double_miller_loop(const mnt4_G1_precomp &prec_P1, + const mnt4_G2_precomp &prec_Q1, + const mnt4_G1_precomp &prec_P2, + const mnt4_G2_precomp &prec_Q2) +{ + return mnt4_double_miller_loop(prec_P1, prec_Q1, prec_P2, prec_Q2); +} + +mnt4_Fq4 mnt4_pp::pairing(const mnt4_G1 &P, + const mnt4_G2 &Q) +{ + return mnt4_pairing(P, Q); +} + +mnt4_Fq4 mnt4_pp::reduced_pairing(const mnt4_G1 &P, + const mnt4_G2 &Q) +{ + return mnt4_reduced_pairing(P, Q); +} + +mnt4_Fq4 mnt4_pp::affine_reduced_pairing(const mnt4_G1 &P, + const mnt4_G2 &Q) +{ + return mnt4_affine_reduced_pairing(P, Q); +} + +} // libsnark diff --git a/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/mnt/mnt4/mnt4_pp.hpp b/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/mnt/mnt4/mnt4_pp.hpp new file mode 100644 index 0000000..f93fc31 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/mnt/mnt4/mnt4_pp.hpp @@ -0,0 +1,80 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for public parameters of MNT4. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef MNT4_PP_HPP_ +#define MNT4_PP_HPP_ + +#include "algebra/curves/public_params.hpp" +#include "algebra/curves/mnt/mnt4/mnt4_init.hpp" +#include "algebra/curves/mnt/mnt4/mnt4_g1.hpp" +#include "algebra/curves/mnt/mnt4/mnt4_g2.hpp" +#include "algebra/curves/mnt/mnt4/mnt4_pairing.hpp" + +namespace libsnark { + +class mnt4_pp { +public: + typedef mnt4_Fr Fp_type; + typedef mnt4_G1 G1_type; + typedef mnt4_G2 G2_type; + typedef mnt4_G1_precomp G1_precomp_type; + typedef mnt4_G2_precomp G2_precomp_type; + typedef mnt4_affine_ate_G1_precomputation affine_ate_G1_precomp_type; + typedef mnt4_affine_ate_G2_precomputation affine_ate_G2_precomp_type; + typedef mnt4_Fq Fq_type; + typedef mnt4_Fq2 Fqe_type; + typedef mnt4_Fq4 Fqk_type; + typedef mnt4_GT GT_type; + + static const bool has_affine_pairing = true; + + static void init_public_params(); + static mnt4_GT final_exponentiation(const mnt4_Fq4 &elt); + + static mnt4_G1_precomp precompute_G1(const mnt4_G1 &P); + static mnt4_G2_precomp precompute_G2(const mnt4_G2 &Q); + + static mnt4_Fq4 miller_loop(const mnt4_G1_precomp &prec_P, + const mnt4_G2_precomp &prec_Q); + + static mnt4_affine_ate_G1_precomputation affine_ate_precompute_G1(const mnt4_G1 &P); + static mnt4_affine_ate_G2_precomputation affine_ate_precompute_G2(const mnt4_G2 &Q); + static mnt4_Fq4 affine_ate_miller_loop(const mnt4_affine_ate_G1_precomputation &prec_P, + const mnt4_affine_ate_G2_precomputation &prec_Q); + + static mnt4_Fq4 affine_ate_e_over_e_miller_loop(const mnt4_affine_ate_G1_precomputation &prec_P1, + const mnt4_affine_ate_G2_precomputation &prec_Q1, + const mnt4_affine_ate_G1_precomputation &prec_P2, + const mnt4_affine_ate_G2_precomputation &prec_Q2); + static mnt4_Fq4 affine_ate_e_times_e_over_e_miller_loop(const mnt4_affine_ate_G1_precomputation &prec_P1, + const mnt4_affine_ate_G2_precomputation &prec_Q1, + const mnt4_affine_ate_G1_precomputation &prec_P2, + const mnt4_affine_ate_G2_precomputation &prec_Q2, + const mnt4_affine_ate_G1_precomputation &prec_P3, + const mnt4_affine_ate_G2_precomputation &prec_Q3); + + static mnt4_Fq4 double_miller_loop(const mnt4_G1_precomp &prec_P1, + const mnt4_G2_precomp &prec_Q1, + const mnt4_G1_precomp &prec_P2, + const mnt4_G2_precomp &prec_Q2); + + /* the following are used in test files */ + static mnt4_Fq4 pairing(const mnt4_G1 &P, + const mnt4_G2 &Q); + static mnt4_Fq4 reduced_pairing(const mnt4_G1 &P, + const mnt4_G2 &Q); + static mnt4_Fq4 affine_reduced_pairing(const mnt4_G1 &P, + const mnt4_G2 &Q); +}; + +} // libsnark + +#endif // MNT4_PP_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/mnt/mnt46_common.cpp b/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/mnt/mnt46_common.cpp new file mode 100644 index 0000000..50248f5 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/mnt/mnt46_common.cpp @@ -0,0 +1,21 @@ +/** @file + ***************************************************************************** + + Implementation of functionality that is shared among MNT curves. + + See mnt46_common.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include "algebra/curves/mnt/mnt46_common.hpp" + +namespace libsnark { + +bigint mnt46_modulus_A; +bigint mnt46_modulus_B; + +} // libsnark diff --git a/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/mnt/mnt46_common.hpp b/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/mnt/mnt46_common.hpp new file mode 100644 index 0000000..b1e3080 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/mnt/mnt46_common.hpp @@ -0,0 +1,30 @@ +/** @file + ***************************************************************************** + + Declaration of functionality that is shared among MNT curves. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef MNT46_COMMON_HPP_ +#define MNT46_COMMON_HPP_ + +#include "algebra/fields/bigint.hpp" + +namespace libsnark { + +const mp_size_t mnt46_A_bitcount = 298; +const mp_size_t mnt46_B_bitcount = 298; + +const mp_size_t mnt46_A_limbs = (mnt46_A_bitcount+GMP_NUMB_BITS-1)/GMP_NUMB_BITS; +const mp_size_t mnt46_B_limbs = (mnt46_B_bitcount+GMP_NUMB_BITS-1)/GMP_NUMB_BITS; + +extern bigint mnt46_modulus_A; +extern bigint mnt46_modulus_B; + +} // libsnark + +#endif diff --git a/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/mnt/mnt6/mnt6_g1.cpp b/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/mnt/mnt6/mnt6_g1.cpp new file mode 100644 index 0000000..b0181de --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/mnt/mnt6/mnt6_g1.cpp @@ -0,0 +1,504 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for the MNT6 G1 group. + + See mnt6_g1.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include "algebra/curves/mnt/mnt6/mnt6_g1.hpp" + +namespace libsnark { + +#ifdef PROFILE_OP_COUNTS +long long mnt6_G1::add_cnt = 0; +long long mnt6_G1::dbl_cnt = 0; +#endif + +std::vector mnt6_G1::wnaf_window_table; +std::vector mnt6_G1::fixed_base_exp_window_table; +mnt6_G1 mnt6_G1::G1_zero; +mnt6_G1 mnt6_G1::G1_one; +mnt6_Fq mnt6_G1::coeff_a; +mnt6_Fq mnt6_G1::coeff_b; + +mnt6_G1::mnt6_G1() +{ + this->X_ = G1_zero.X_; + this->Y_ = G1_zero.Y_; + this->Z_ = G1_zero.Z_; +} + +void mnt6_G1::print() const +{ + if (this->is_zero()) + { + printf("O\n"); + } + else + { + mnt6_G1 copy(*this); + copy.to_affine_coordinates(); + gmp_printf("(%Nd , %Nd)\n", + copy.X_.as_bigint().data, mnt6_Fq::num_limbs, + copy.Y_.as_bigint().data, mnt6_Fq::num_limbs); + } +} + +void mnt6_G1::print_coordinates() const +{ + if (this->is_zero()) + { + printf("O\n"); + } + else + { + gmp_printf("(%Nd : %Nd : %Nd)\n", + this->X_.as_bigint().data, mnt6_Fq::num_limbs, + this->Y_.as_bigint().data, mnt6_Fq::num_limbs, + this->Z_.as_bigint().data, mnt6_Fq::num_limbs); + } +} + +void mnt6_G1::to_affine_coordinates() +{ + if (this->is_zero()) + { + this->X_ = mnt6_Fq::zero(); + this->Y_ = mnt6_Fq::one(); + this->Z_ = mnt6_Fq::zero(); + } + else + { + const mnt6_Fq Z_inv = Z_.inverse(); + this->X_ = this->X_ * Z_inv; + this->Y_ = this->Y_ * Z_inv; + this->Z_ = mnt6_Fq::one(); + } +} + +void mnt6_G1::to_special() +{ + this->to_affine_coordinates(); +} + +bool mnt6_G1::is_special() const +{ + return (this->is_zero() || this->Z_ == mnt6_Fq::one()); +} + +bool mnt6_G1::is_zero() const +{ + return (this->X_.is_zero() && this->Z_.is_zero()); +} + +bool mnt6_G1::operator==(const mnt6_G1 &other) const +{ + if (this->is_zero()) + { + return other.is_zero(); + } + + if (other.is_zero()) + { + return false; + } + + /* now neither is O */ + + // X1/Z1 = X2/Z2 <=> X1*Z2 = X2*Z1 + if ((this->X_ * other.Z_) != (other.X_ * this->Z_)) + { + return false; + } + + // Y1/Z1 = Y2/Z2 <=> Y1*Z2 = Y2*Z1 + if ((this->Y_ * other.Z_) != (other.Y_ * this->Z_)) + { + return false; + } + + return true; +} + +bool mnt6_G1::operator!=(const mnt6_G1& other) const +{ + return !(operator==(other)); +} + +mnt6_G1 mnt6_G1::operator+(const mnt6_G1 &other) const +{ + // handle special cases having to do with O + if (this->is_zero()) + { + return other; + } + + if (other.is_zero()) + { + return *this; + } + + // no need to handle points of order 2,4 + // (they cannot exist in a prime-order subgroup) + + // handle double case, and then all the rest + /* + The code below is equivalent to (but faster than) the snippet below: + + if (this->operator==(other)) + { + return this->dbl(); + } + else + { + return this->add(other); + } + */ + + const mnt6_Fq X1Z2 = (this->X_) * (other.Z_); // X1Z2 = X1*Z2 + const mnt6_Fq X2Z1 = (this->Z_) * (other.X_); // X2Z1 = X2*Z1 + + // (used both in add and double checks) + + const mnt6_Fq Y1Z2 = (this->Y_) * (other.Z_); // Y1Z2 = Y1*Z2 + const mnt6_Fq Y2Z1 = (this->Z_) * (other.Y_); // Y2Z1 = Y2*Z1 + + if (X1Z2 == X2Z1 && Y1Z2 == Y2Z1) + { + // perform dbl case + const mnt6_Fq XX = (this->X_).squared(); // XX = X1^2 + const mnt6_Fq ZZ = (this->Z_).squared(); // ZZ = Z1^2 + const mnt6_Fq w = mnt6_G1::coeff_a * ZZ + (XX + XX + XX); // w = a*ZZ + 3*XX + const mnt6_Fq Y1Z1 = (this->Y_) * (this->Z_); + const mnt6_Fq s = Y1Z1 + Y1Z1; // s = 2*Y1*Z1 + const mnt6_Fq ss = s.squared(); // ss = s^2 + const mnt6_Fq sss = s * ss; // sss = s*ss + const mnt6_Fq R = (this->Y_) * s; // R = Y1*s + const mnt6_Fq RR = R.squared(); // RR = R^2 + const mnt6_Fq B = ((this->X_)+R).squared()-XX-RR; // B = (X1+R)^2 - XX - RR + const mnt6_Fq h = w.squared() - (B+B); // h = w^2 - 2*B + const mnt6_Fq X3 = h * s; // X3 = h*s + const mnt6_Fq Y3 = w * (B-h)-(RR+RR); // Y3 = w*(B-h) - 2*RR + const mnt6_Fq Z3 = sss; // Z3 = sss + + return mnt6_G1(X3, Y3, Z3); + } + + // if we have arrived here we are in the add case + const mnt6_Fq Z1Z2 = (this->Z_) * (other.Z_); // Z1Z2 = Z1*Z2 + const mnt6_Fq u = Y2Z1 - Y1Z2; // u = Y2*Z1-Y1Z2 + const mnt6_Fq uu = u.squared(); // uu = u^2 + const mnt6_Fq v = X2Z1 - X1Z2; // v = X2*Z1-X1Z2 + const mnt6_Fq vv = v.squared(); // vv = v^2 + const mnt6_Fq vvv = v * vv; // vvv = v*vv + const mnt6_Fq R = vv * X1Z2; // R = vv*X1Z2 + const mnt6_Fq A = uu * Z1Z2 - (vvv + R + R); // A = uu*Z1Z2 - vvv - 2*R + const mnt6_Fq X3 = v * A; // X3 = v*A + const mnt6_Fq Y3 = u * (R-A) - vvv * Y1Z2; // Y3 = u*(R-A) - vvv*Y1Z2 + const mnt6_Fq Z3 = vvv * Z1Z2; // Z3 = vvv*Z1Z2 + + return mnt6_G1(X3, Y3, Z3); +} + +mnt6_G1 mnt6_G1::operator-() const +{ + return mnt6_G1(this->X_, -(this->Y_), this->Z_); +} + + +mnt6_G1 mnt6_G1::operator-(const mnt6_G1 &other) const +{ + return (*this) + (-other); +} + +mnt6_G1 mnt6_G1::add(const mnt6_G1 &other) const +{ + // handle special cases having to do with O + if (this->is_zero()) + { + return other; + } + + if (other.is_zero()) + { + return (*this); + } + + // no need to handle points of order 2,4 + // (they cannot exist in a prime-order subgroup) + + // handle double case + if (this->operator==(other)) + { + return this->dbl(); + } + +#ifdef PROFILE_OP_COUNTS + this->add_cnt++; +#endif + // NOTE: does not handle O and pts of order 2,4 + // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-projective.html#addition-add-1998-cmo-2 + + const mnt6_Fq Y1Z2 = (this->Y_) * (other.Z_); // Y1Z2 = Y1*Z2 + const mnt6_Fq X1Z2 = (this->X_) * (other.Z_); // X1Z2 = X1*Z2 + const mnt6_Fq Z1Z2 = (this->Z_) * (other.Z_); // Z1Z2 = Z1*Z2 + const mnt6_Fq u = (other.Y_) * (this->Z_) - Y1Z2; // u = Y2*Z1-Y1Z2 + const mnt6_Fq uu = u.squared(); // uu = u^2 + const mnt6_Fq v = (other.X_) * (this->Z_) - X1Z2; // v = X2*Z1-X1Z2 + const mnt6_Fq vv = v.squared(); // vv = v^2 + const mnt6_Fq vvv = v * vv; // vvv = v*vv + const mnt6_Fq R = vv * X1Z2; // R = vv*X1Z2 + const mnt6_Fq A = uu * Z1Z2 - (vvv + R + R); // A = uu*Z1Z2 - vvv - 2*R + const mnt6_Fq X3 = v * A; // X3 = v*A + const mnt6_Fq Y3 = u * (R-A) - vvv * Y1Z2; // Y3 = u*(R-A) - vvv*Y1Z2 + const mnt6_Fq Z3 = vvv * Z1Z2; // Z3 = vvv*Z1Z2 + + return mnt6_G1(X3, Y3, Z3); +} + +mnt6_G1 mnt6_G1::mixed_add(const mnt6_G1 &other) const +{ +#ifdef PROFILE_OP_COUNTS + this->add_cnt++; +#endif + // NOTE: does not handle O and pts of order 2,4 + // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-projective.html#addition-add-1998-cmo-2 + //assert(other.Z == mnt6_Fq::one()); + + if (this->is_zero()) + { + return other; + } + + if (other.is_zero()) + { + return (*this); + } + +#ifdef DEBUG + assert(other.is_special()); +#endif + + const mnt6_Fq &X1Z2 = (this->X_); // X1Z2 = X1*Z2 (but other is special and not zero) + const mnt6_Fq X2Z1 = (this->Z_) * (other.X_); // X2Z1 = X2*Z1 + + // (used both in add and double checks) + + const mnt6_Fq &Y1Z2 = (this->Y_); // Y1Z2 = Y1*Z2 (but other is special and not zero) + const mnt6_Fq Y2Z1 = (this->Z_) * (other.Y_); // Y2Z1 = Y2*Z1 + + if (X1Z2 == X2Z1 && Y1Z2 == Y2Z1) + { + return this->dbl(); + } + + mnt6_Fq u = Y2Z1 - this->Y_; // u = Y2*Z1-Y1 + mnt6_Fq uu = u.squared(); // uu = u2 + mnt6_Fq v = X2Z1 - this->X_; // v = X2*Z1-X1 + mnt6_Fq vv = v.squared(); // vv = v2 + mnt6_Fq vvv = v*vv; // vvv = v*vv + mnt6_Fq R = vv * this->X_; // R = vv*X1 + mnt6_Fq A = uu * this->Z_ - vvv - R - R; // A = uu*Z1-vvv-2*R + mnt6_Fq X3 = v * A; // X3 = v*A + mnt6_Fq Y3 = u*(R-A) - vvv * this->Y_; // Y3 = u*(R-A)-vvv*Y1 + mnt6_Fq Z3 = vvv * this->Z_; // Z3 = vvv*Z1 + + return mnt6_G1(X3, Y3, Z3); +} + +mnt6_G1 mnt6_G1::dbl() const +{ +#ifdef PROFILE_OP_COUNTS + this->dbl_cnt++; +#endif + if (this->is_zero()) + { + return (*this); + } + else + { + // NOTE: does not handle O and pts of order 2,4 + // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-projective.html#doubling-dbl-2007-bl + + const mnt6_Fq XX = (this->X_).squared(); // XX = X1^2 + const mnt6_Fq ZZ = (this->Z_).squared(); // ZZ = Z1^2 + const mnt6_Fq w = mnt6_G1::coeff_a * ZZ + (XX + XX + XX); // w = a*ZZ + 3*XX + const mnt6_Fq Y1Z1 = (this->Y_) * (this->Z_); + const mnt6_Fq s = Y1Z1 + Y1Z1; // s = 2*Y1*Z1 + const mnt6_Fq ss = s.squared(); // ss = s^2 + const mnt6_Fq sss = s * ss; // sss = s*ss + const mnt6_Fq R = (this->Y_) * s; // R = Y1*s + const mnt6_Fq RR = R.squared(); // RR = R^2 + const mnt6_Fq B = ((this->X_)+R).squared()-XX-RR; // B = (X1+R)^2 - XX - RR + const mnt6_Fq h = w.squared() - (B+B); // h = w^2 - 2*B + const mnt6_Fq X3 = h * s; // X3 = h*s + const mnt6_Fq Y3 = w * (B-h)-(RR+RR); // Y3 = w*(B-h) - 2*RR + const mnt6_Fq Z3 = sss; // Z3 = sss + + return mnt6_G1(X3, Y3, Z3); + } +} + +bool mnt6_G1::is_well_formed() const +{ + if (this->is_zero()) + { + return true; + } + else + { + /* + y^2 = x^3 + ax + b + + We are using projective, so equation we need to check is actually + + (y/z)^2 = (x/z)^3 + a (x/z) + b + z y^2 = x^3 + a z^2 x + b z^3 + + z (y^2 - b z^2) = x ( x^2 + a z^2) + */ + const mnt6_Fq X2 = this->X_.squared(); + const mnt6_Fq Y2 = this->Y_.squared(); + const mnt6_Fq Z2 = this->Z_.squared(); + + return (this->Z_ * (Y2 - mnt6_G1::coeff_b * Z2) == this->X_ * (X2 + mnt6_G1::coeff_a * Z2)); + } +} + +mnt6_G1 mnt6_G1::zero() +{ + return G1_zero; +} + +mnt6_G1 mnt6_G1::one() +{ + return G1_one; +} + +mnt6_G1 mnt6_G1::random_element() +{ + return (scalar_field::random_element().as_bigint()) * G1_one; +} + +std::ostream& operator<<(std::ostream &out, const mnt6_G1 &g) +{ + mnt6_G1 copy(g); + copy.to_affine_coordinates(); + + out << (copy.is_zero() ? 1 : 0) << OUTPUT_SEPARATOR; +#ifdef NO_PT_COMPRESSION + out << copy.X_ << OUTPUT_SEPARATOR << copy.Y_; +#else + /* storing LSB of Y */ + out << copy.X_ << OUTPUT_SEPARATOR << (copy.Y_.as_bigint().data[0] & 1); +#endif + + return out; +} + +std::istream& operator>>(std::istream &in, mnt6_G1 &g) +{ + char is_zero; + mnt6_Fq tX, tY; + +#ifdef NO_PT_COMPRESSION + in >> is_zero >> tX >> tY; + is_zero -= '0'; +#else + in.read((char*)&is_zero, 1); // this reads is_zero; + is_zero -= '0'; + consume_OUTPUT_SEPARATOR(in); + + unsigned char Y_lsb; + in >> tX; + consume_OUTPUT_SEPARATOR(in); + in.read((char*)&Y_lsb, 1); + Y_lsb -= '0'; + + // y = +/- sqrt(x^3 + a*x + b) + if (!is_zero) + { + mnt6_Fq tX2 = tX.squared(); + mnt6_Fq tY2 = (tX2 + mnt6_G1::coeff_a) * tX + mnt6_G1::coeff_b; + tY = tY2.sqrt(); + + if ((tY.as_bigint().data[0] & 1) != Y_lsb) + { + tY = -tY; + } + } +#endif + // using projective coordinates + if (!is_zero) + { + g.X_ = tX; + g.Y_ = tY; + g.Z_ = mnt6_Fq::one(); + } + else + { + g = mnt6_G1::zero(); + } + + return in; +} + +std::ostream& operator<<(std::ostream& out, const std::vector &v) +{ + out << v.size() << "\n"; + for (const mnt6_G1& t : v) + { + out << t << OUTPUT_NEWLINE; + } + + return out; +} + +std::istream& operator>>(std::istream& in, std::vector &v) +{ + v.clear(); + + size_t s; + in >> s; + consume_newline(in); + + v.reserve(s); + + for (size_t i = 0; i < s; ++i) + { + mnt6_G1 g; + in >> g; + consume_OUTPUT_NEWLINE(in); + v.emplace_back(g); + } + + return in; +} + +template<> +void batch_to_special_all_non_zeros(std::vector &vec) +{ + std::vector Z_vec; + Z_vec.reserve(vec.size()); + + for (auto &el: vec) + { + Z_vec.emplace_back(el.Z()); + } + batch_invert(Z_vec); + + const mnt6_Fq one = mnt6_Fq::one(); + + for (size_t i = 0; i < vec.size(); ++i) + { + vec[i] = mnt6_G1(vec[i].X() * Z_vec[i], vec[i].Y() * Z_vec[i], one); + } +} + +} // libsnark diff --git a/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/mnt/mnt6/mnt6_g1.hpp b/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/mnt/mnt6/mnt6_g1.hpp new file mode 100644 index 0000000..e03b403 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/mnt/mnt6/mnt6_g1.hpp @@ -0,0 +1,109 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for the MNT6 G1 group. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef MNT6_G1_HPP_ +#define MNT6_G1_HPP_ + +#include + +#include "algebra/curves/curve_utils.hpp" +#include "algebra/curves/mnt/mnt6/mnt6_init.hpp" + +namespace libsnark { + +class mnt6_G1; +std::ostream& operator<<(std::ostream &, const mnt6_G1&); +std::istream& operator>>(std::istream &, mnt6_G1&); + +class mnt6_G1 { +private: + mnt6_Fq X_, Y_, Z_; +public: +#ifdef PROFILE_OP_COUNTS + static long long add_cnt; + static long long dbl_cnt; +#endif + static std::vector wnaf_window_table; + static std::vector fixed_base_exp_window_table; + static mnt6_G1 G1_zero; + static mnt6_G1 G1_one; + static mnt6_Fq coeff_a; + static mnt6_Fq coeff_b; + + typedef mnt6_Fq base_field; + typedef mnt6_Fr scalar_field; + + // using projective coordinates + mnt6_G1(); + mnt6_G1(const mnt6_Fq& X, const mnt6_Fq& Y) : X_(X), Y_(Y), Z_(base_field::one()) {} + mnt6_G1(const mnt6_Fq& X, const mnt6_Fq& Y, const mnt6_Fq& Z) : X_(X), Y_(Y), Z_(Z) {} + + mnt6_Fq X() const { return X_; } + mnt6_Fq Y() const { return Y_; } + mnt6_Fq Z() const { return Z_; } + + void print() const; + void print_coordinates() const; + + void to_affine_coordinates(); + void to_special(); + bool is_special() const; + + bool is_zero() const; + + bool operator==(const mnt6_G1 &other) const; + bool operator!=(const mnt6_G1 &other) const; + + mnt6_G1 operator+(const mnt6_G1 &other) const; + mnt6_G1 operator-() const; + mnt6_G1 operator-(const mnt6_G1 &other) const; + + mnt6_G1 add(const mnt6_G1 &other) const; + mnt6_G1 mixed_add(const mnt6_G1 &other) const; + mnt6_G1 dbl() const; + + bool is_well_formed() const; + + static mnt6_G1 zero(); + static mnt6_G1 one(); + static mnt6_G1 random_element(); + + static size_t size_in_bits() { return base_field::size_in_bits() + 1; } + static bigint base_field_char() { return base_field::field_char(); } + static bigint order() { return scalar_field::field_char(); } + + friend std::ostream& operator<<(std::ostream &out, const mnt6_G1 &g); + friend std::istream& operator>>(std::istream &in, mnt6_G1 &g); +}; + +template +mnt6_G1 operator*(const bigint &lhs, const mnt6_G1 &rhs) +{ + return scalar_mul(rhs, lhs); +} + +template& modulus_p> +mnt6_G1 operator*(const Fp_model &lhs, const mnt6_G1 &rhs) +{ + return scalar_mul(rhs, lhs.as_bigint()); +} + +std::ostream& operator<<(std::ostream& out, const std::vector &v); +std::istream& operator>>(std::istream& in, std::vector &v); + +template +void batch_to_special_all_non_zeros(std::vector &vec); +template<> +void batch_to_special_all_non_zeros(std::vector &vec); + +} // libsnark + +#endif // MNT6_G1_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/mnt/mnt6/mnt6_g2.cpp b/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/mnt/mnt6/mnt6_g2.cpp new file mode 100644 index 0000000..d39c6a7 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/mnt/mnt6/mnt6_g2.cpp @@ -0,0 +1,503 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for the MNT6 G2 group. + + See mnt6_g2.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include "algebra/curves/mnt/mnt6/mnt6_g2.hpp" + +namespace libsnark { + +#ifdef PROFILE_OP_COUNTS +long long mnt6_G2::add_cnt = 0; +long long mnt6_G2::dbl_cnt = 0; +#endif + +std::vector mnt6_G2::wnaf_window_table; +std::vector mnt6_G2::fixed_base_exp_window_table; +mnt6_Fq3 mnt6_G2::twist; +mnt6_Fq3 mnt6_G2::coeff_a; +mnt6_Fq3 mnt6_G2::coeff_b; +mnt6_G2 mnt6_G2::G2_zero; +mnt6_G2 mnt6_G2::G2_one; + +mnt6_G2::mnt6_G2() +{ + this->X_ = G2_zero.X_; + this->Y_ = G2_zero.Y_; + this->Z_ = G2_zero.Z_; +} + +mnt6_Fq3 mnt6_G2::mul_by_a(const mnt6_Fq3 &elt) +{ + return mnt6_Fq3(mnt6_twist_mul_by_a_c0 * elt.c1, mnt6_twist_mul_by_a_c1 * elt.c2, mnt6_twist_mul_by_a_c2 * elt.c0); +} + +mnt6_Fq3 mnt6_G2::mul_by_b(const mnt6_Fq3 &elt) +{ + return mnt6_Fq3(mnt6_twist_mul_by_b_c0 * elt.c0, mnt6_twist_mul_by_b_c1 * elt.c1, mnt6_twist_mul_by_b_c2 * elt.c2); +} + +void mnt6_G2::print() const +{ + if (this->is_zero()) + { + printf("O\n"); + } + else + { + mnt6_G2 copy(*this); + copy.to_affine_coordinates(); + gmp_printf("(%Nd*z^2 + %Nd*z + %Nd , %Nd*z^2 + %Nd*z + %Nd)\n", + copy.X_.c2.as_bigint().data, mnt6_Fq::num_limbs, + copy.X_.c1.as_bigint().data, mnt6_Fq::num_limbs, + copy.X_.c0.as_bigint().data, mnt6_Fq::num_limbs, + copy.Y_.c2.as_bigint().data, mnt6_Fq::num_limbs, + copy.Y_.c1.as_bigint().data, mnt6_Fq::num_limbs, + copy.Y_.c0.as_bigint().data, mnt6_Fq::num_limbs); + } +} + +void mnt6_G2::print_coordinates() const +{ + if (this->is_zero()) + { + printf("O\n"); + } + else + { + gmp_printf("(%Nd*z^2 + %Nd*z + %Nd : %Nd*z^2 + %Nd*z + %Nd : %Nd*z^2 + %Nd*z + %Nd)\n", + this->X_.c2.as_bigint().data, mnt6_Fq::num_limbs, + this->X_.c1.as_bigint().data, mnt6_Fq::num_limbs, + this->X_.c0.as_bigint().data, mnt6_Fq::num_limbs, + this->Y_.c2.as_bigint().data, mnt6_Fq::num_limbs, + this->Y_.c1.as_bigint().data, mnt6_Fq::num_limbs, + this->Y_.c0.as_bigint().data, mnt6_Fq::num_limbs, + this->Z_.c2.as_bigint().data, mnt6_Fq::num_limbs, + this->Z_.c1.as_bigint().data, mnt6_Fq::num_limbs, + this->Z_.c0.as_bigint().data, mnt6_Fq::num_limbs); + } +} + +void mnt6_G2::to_affine_coordinates() +{ + if (this->is_zero()) + { + this->X_ = mnt6_Fq3::zero(); + this->Y_ = mnt6_Fq3::one(); + this->Z_ = mnt6_Fq3::zero(); + } + else + { + const mnt6_Fq3 Z_inv = Z_.inverse(); + this->X_ = this->X_ * Z_inv; + this->Y_ = this->Y_ * Z_inv; + this->Z_ = mnt6_Fq3::one(); + } +} + +void mnt6_G2::to_special() +{ + this->to_affine_coordinates(); +} + +bool mnt6_G2::is_special() const +{ + return (this->is_zero() || this->Z_ == mnt6_Fq3::one()); +} + +bool mnt6_G2::is_zero() const +{ + // TODO: use zero for here + return (this->X_.is_zero() && this->Z_.is_zero()); +} + +bool mnt6_G2::operator==(const mnt6_G2 &other) const +{ + if (this->is_zero()) + { + return other.is_zero(); + } + + if (other.is_zero()) + { + return false; + } + + /* now neither is O */ + + // X1/Z1 = X2/Z2 <=> X1*Z2 = X2*Z1 + if ((this->X_ * other.Z_) != (other.X_ * this->Z_)) + { + return false; + } + + // Y1/Z1 = Y2/Z2 <=> Y1*Z2 = Y2*Z1 + if ((this->Y_ * other.Z_) != (other.Y_ * this->Z_)) + { + return false; + } + + return true; +} + +bool mnt6_G2::operator!=(const mnt6_G2& other) const +{ + return !(operator==(other)); +} + +mnt6_G2 mnt6_G2::operator+(const mnt6_G2 &other) const +{ + // handle special cases having to do with O + if (this->is_zero()) + { + return other; + } + + if (other.is_zero()) + { + return *this; + } + + // no need to handle points of order 2,4 + // (they cannot exist in a prime-order subgroup) + + // handle double case, and then all the rest + /* + The code below is equivalent to (but faster than) the snippet below: + + if (this->operator==(other)) + { + return this->dbl(); + } + else + { + return this->add(other); + } + */ + + const mnt6_Fq3 X1Z2 = (this->X_) * (other.Z_); // X1Z2 = X1*Z2 + const mnt6_Fq3 X2Z1 = (this->Z_) * (other.X_); // X2Z1 = X2*Z1 + + // (used both in add and double checks) + + const mnt6_Fq3 Y1Z2 = (this->Y_) * (other.Z_); // Y1Z2 = Y1*Z2 + const mnt6_Fq3 Y2Z1 = (this->Z_) * (other.Y_); // Y2Z1 = Y2*Z1 + + if (X1Z2 == X2Z1 && Y1Z2 == Y2Z1) + { + // perform dbl case + const mnt6_Fq3 XX = (this->X_).squared(); // XX = X1^2 + const mnt6_Fq3 ZZ = (this->Z_).squared(); // ZZ = Z1^2 + const mnt6_Fq3 w = mnt6_G2::mul_by_a(ZZ) + (XX + XX + XX); // w = a*ZZ + 3*XX + const mnt6_Fq3 Y1Z1 = (this->Y_) * (this->Z_); + const mnt6_Fq3 s = Y1Z1 + Y1Z1; // s = 2*Y1*Z1 + const mnt6_Fq3 ss = s.squared(); // ss = s^2 + const mnt6_Fq3 sss = s * ss; // sss = s*ss + const mnt6_Fq3 R = (this->Y_) * s; // R = Y1*s + const mnt6_Fq3 RR = R.squared(); // RR = R^2 + const mnt6_Fq3 B = ((this->X_)+R).squared()-XX-RR; // B = (X1+R)^2 - XX - RR + const mnt6_Fq3 h = w.squared() - (B+B); // h = w^2 - 2*B + const mnt6_Fq3 X3 = h * s; // X3 = h*s + const mnt6_Fq3 Y3 = w * (B-h)-(RR+RR); // Y3 = w*(B-h) - 2*RR + const mnt6_Fq3 Z3 = sss; // Z3 = sss + + return mnt6_G2(X3, Y3, Z3); + } + + // if we have arrived here we are in the add case + const mnt6_Fq3 Z1Z2 = (this->Z_) * (other.Z_); // Z1Z2 = Z1*Z2 + const mnt6_Fq3 u = Y2Z1 - Y1Z2; // u = Y2*Z1-Y1Z2 + const mnt6_Fq3 uu = u.squared(); // uu = u^2 + const mnt6_Fq3 v = X2Z1 - X1Z2; // v = X2*Z1-X1Z2 + const mnt6_Fq3 vv = v.squared(); // vv = v^2 + const mnt6_Fq3 vvv = v * vv; // vvv = v*vv + const mnt6_Fq3 R = vv * X1Z2; // R = vv*X1Z2 + const mnt6_Fq3 A = uu * Z1Z2 - (vvv + R + R); // A = uu*Z1Z2 - vvv - 2*R + const mnt6_Fq3 X3 = v * A; // X3 = v*A + const mnt6_Fq3 Y3 = u * (R-A) - vvv * Y1Z2; // Y3 = u*(R-A) - vvv*Y1Z2 + const mnt6_Fq3 Z3 = vvv * Z1Z2; // Z3 = vvv*Z1Z2 + + return mnt6_G2(X3, Y3, Z3); +} + +mnt6_G2 mnt6_G2::operator-() const +{ + return mnt6_G2(this->X_, -(this->Y_), this->Z_); +} + + +mnt6_G2 mnt6_G2::operator-(const mnt6_G2 &other) const +{ + return (*this) + (-other); +} + +mnt6_G2 mnt6_G2::add(const mnt6_G2 &other) const +{ + // handle special cases having to do with O + if (this->is_zero()) + { + return other; + } + + if (other.is_zero()) + { + return (*this); + } + + // no need to handle points of order 2,4 + // (they cannot exist in a prime-order subgroup) + + // handle double case + if (this->operator==(other)) + { + return this->dbl(); + } + +#ifdef PROFILE_OP_COUNTS + this->add_cnt++; +#endif + // NOTE: does not handle O and pts of order 2,4 + // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-projective.html#addition-add-1998-cmo-2 + + const mnt6_Fq3 Y1Z2 = (this->Y_) * (other.Z_); // Y1Z2 = Y1*Z2 + const mnt6_Fq3 X1Z2 = (this->X_) * (other.Z_); // X1Z2 = X1*Z2 + const mnt6_Fq3 Z1Z2 = (this->Z_) * (other.Z_); // Z1Z2 = Z1*Z2 + const mnt6_Fq3 u = (other.Y_) * (this->Z_) - Y1Z2; // u = Y2*Z1-Y1Z2 + const mnt6_Fq3 uu = u.squared(); // uu = u^2 + const mnt6_Fq3 v = (other.X_) * (this->Z_) - X1Z2; // v = X2*Z1-X1Z2 + const mnt6_Fq3 vv = v.squared(); // vv = v^2 + const mnt6_Fq3 vvv = v * vv; // vvv = v*vv + const mnt6_Fq3 R = vv * X1Z2; // R = vv*X1Z2 + const mnt6_Fq3 A = uu * Z1Z2 - (vvv + R + R); // A = uu*Z1Z2 - vvv - 2*R + const mnt6_Fq3 X3 = v * A; // X3 = v*A + const mnt6_Fq3 Y3 = u * (R-A) - vvv * Y1Z2; // Y3 = u*(R-A) - vvv*Y1Z2 + const mnt6_Fq3 Z3 = vvv * Z1Z2; // Z3 = vvv*Z1Z2 + + return mnt6_G2(X3, Y3, Z3); +} + +mnt6_G2 mnt6_G2::mixed_add(const mnt6_G2 &other) const +{ +#ifdef PROFILE_OP_COUNTS + this->add_cnt++; +#endif + // NOTE: does not handle O and pts of order 2,4 + // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-projective.html#addition-add-1998-cmo-2 + //assert(other.Z == mnt6_Fq3::one()); + + if (this->is_zero()) + { + return other; + } + + if (other.is_zero()) + { + return (*this); + } + +#ifdef DEBUG + assert(other.is_special()); +#endif + + const mnt6_Fq3 &X1Z2 = (this->X_); // X1Z2 = X1*Z2 (but other is special and not zero) + const mnt6_Fq3 X2Z1 = (this->Z_) * (other.X_); // X2Z1 = X2*Z1 + + // (used both in add and double checks) + + const mnt6_Fq3 &Y1Z2 = (this->Y_); // Y1Z2 = Y1*Z2 (but other is special and not zero) + const mnt6_Fq3 Y2Z1 = (this->Z_) * (other.Y_); // Y2Z1 = Y2*Z1 + + if (X1Z2 == X2Z1 && Y1Z2 == Y2Z1) + { + return this->dbl(); + } + + const mnt6_Fq3 u = Y2Z1 - this->Y_; // u = Y2*Z1-Y1 + const mnt6_Fq3 uu = u.squared(); // uu = u2 + const mnt6_Fq3 v = X2Z1 - this->X_; // v = X2*Z1-X1 + const mnt6_Fq3 vv = v.squared(); // vv = v2 + const mnt6_Fq3 vvv = v*vv; // vvv = v*vv + const mnt6_Fq3 R = vv * this->X_; // R = vv*X1 + const mnt6_Fq3 A = uu * this->Z_ - vvv - R - R; // A = uu*Z1-vvv-2*R + const mnt6_Fq3 X3 = v * A; // X3 = v*A + const mnt6_Fq3 Y3 = u*(R-A) - vvv * this->Y_; // Y3 = u*(R-A)-vvv*Y1 + const mnt6_Fq3 Z3 = vvv * this->Z_; // Z3 = vvv*Z1 + + return mnt6_G2(X3, Y3, Z3); +} + +mnt6_G2 mnt6_G2::dbl() const +{ +#ifdef PROFILE_OP_COUNTS + this->dbl_cnt++; +#endif + if (this->is_zero()) + { + return (*this); + } + else + { + // NOTE: does not handle O and pts of order 2,4 + // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-projective.html#doubling-dbl-2007-bl + + const mnt6_Fq3 XX = (this->X_).squared(); // XX = X1^2 + const mnt6_Fq3 ZZ = (this->Z_).squared(); // ZZ = Z1^2 + const mnt6_Fq3 w = mnt6_G2::mul_by_a(ZZ) + (XX + XX + XX); // w = a*ZZ + 3*XX + const mnt6_Fq3 Y1Z1 = (this->Y_) * (this->Z_); + const mnt6_Fq3 s = Y1Z1 + Y1Z1; // s = 2*Y1*Z1 + const mnt6_Fq3 ss = s.squared(); // ss = s^2 + const mnt6_Fq3 sss = s * ss; // sss = s*ss + const mnt6_Fq3 R = (this->Y_) * s; // R = Y1*s + const mnt6_Fq3 RR = R.squared(); // RR = R^2 + const mnt6_Fq3 B = ((this->X_)+R).squared()-XX-RR; // B = (X1+R)^2 - XX - RR + const mnt6_Fq3 h = w.squared() - (B+B); // h = w^2-2*B + const mnt6_Fq3 X3 = h * s; // X3 = h*s + const mnt6_Fq3 Y3 = w * (B-h)-(RR+RR); // Y3 = w*(B-h) - 2*RR + const mnt6_Fq3 Z3 = sss; // Z3 = sss + + return mnt6_G2(X3, Y3, Z3); + } +} + +mnt6_G2 mnt6_G2::mul_by_q() const +{ + return mnt6_G2(mnt6_twist_mul_by_q_X * (this->X_).Frobenius_map(1), + mnt6_twist_mul_by_q_Y * (this->Y_).Frobenius_map(1), + (this->Z_).Frobenius_map(1)); +} + +bool mnt6_G2::is_well_formed() const +{ + if (this->is_zero()) + { + return true; + } + else + { + + /* + y^2 = x^3 + ax + b + + We are using projective, so equation we need to check is actually + + (y/z)^2 = (x/z)^3 + a (x/z) + b + z y^2 = x^3 + a z^2 x + b z^3 + + z (y^2 - b z^2) = x ( x^2 + a z^2) + */ + const mnt6_Fq3 X2 = this->X_.squared(); + const mnt6_Fq3 Y2 = this->Y_.squared(); + const mnt6_Fq3 Z2 = this->Z_.squared(); + const mnt6_Fq3 aZ2 = mnt6_twist_coeff_a * Z2; + + return (this->Z_ * (Y2 - mnt6_twist_coeff_b * Z2) == this->X_ * (X2 + aZ2)); + } +} + +mnt6_G2 mnt6_G2::zero() +{ + return G2_zero; +} + +mnt6_G2 mnt6_G2::one() +{ + return G2_one; +} + +mnt6_G2 mnt6_G2::random_element() +{ + return (mnt6_Fr::random_element().as_bigint()) * G2_one; +} + +std::ostream& operator<<(std::ostream &out, const mnt6_G2 &g) +{ + mnt6_G2 copy(g); + copy.to_affine_coordinates(); + + out << (copy.is_zero() ? 1 : 0) << OUTPUT_SEPARATOR; +#ifdef NO_PT_COMPRESSION + out << copy.X_ << OUTPUT_SEPARATOR << copy.Y_; +#else + /* storing LSB of Y */ + out << copy.X_ << OUTPUT_SEPARATOR << (copy.Y_.c0.as_bigint().data[0] & 1); +#endif + + return out; +} + +std::istream& operator>>(std::istream &in, mnt6_G2 &g) +{ + char is_zero; + mnt6_Fq3 tX, tY; + +#ifdef NO_PT_COMPRESSION + in >> is_zero >> tX >> tY; + is_zero -= '0'; +#else + in.read((char*)&is_zero, 1); // this reads is_zero; + is_zero -= '0'; + consume_OUTPUT_SEPARATOR(in); + + unsigned char Y_lsb; + in >> tX; + consume_OUTPUT_SEPARATOR(in); + in.read((char*)&Y_lsb, 1); + Y_lsb -= '0'; + + // y = +/- sqrt(x^3 + a*x + b) + if (!is_zero) + { + const mnt6_Fq3 tX2 = tX.squared(); + const mnt6_Fq3 tY2 = (tX2 + mnt6_twist_coeff_a) * tX + mnt6_twist_coeff_b; + tY = tY2.sqrt(); + + if ((tY.c0.as_bigint().data[0] & 1) != Y_lsb) + { + tY = -tY; + } + } +#endif + // using projective coordinates + if (!is_zero) + { + g.X_ = tX; + g.Y_ = tY; + g.Z_ = mnt6_Fq3::one(); + } + else + { + g = mnt6_G2::zero(); + } + + return in; +} + +template<> +void batch_to_special_all_non_zeros(std::vector &vec) +{ + std::vector Z_vec; + Z_vec.reserve(vec.size()); + + for (auto &el: vec) + { + Z_vec.emplace_back(el.Z()); + } + batch_invert(Z_vec); + + const mnt6_Fq3 one = mnt6_Fq3::one(); + + for (size_t i = 0; i < vec.size(); ++i) + { + vec[i] = mnt6_G2(vec[i].X() * Z_vec[i], vec[i].Y() * Z_vec[i], one); + } +} + +} // libsnark diff --git a/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/mnt/mnt6/mnt6_g2.hpp b/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/mnt/mnt6/mnt6_g2.hpp new file mode 100644 index 0000000..b14cadb --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/mnt/mnt6/mnt6_g2.hpp @@ -0,0 +1,111 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for the MNT6 G2 group. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef MNT6_G2_HPP_ +#define MNT6_G2_HPP_ + +#include + +#include "algebra/curves/curve_utils.hpp" +#include "algebra/curves/mnt/mnt6/mnt6_init.hpp" + +namespace libsnark { + +class mnt6_G2; +std::ostream& operator<<(std::ostream &, const mnt6_G2&); +std::istream& operator>>(std::istream &, mnt6_G2&); + +class mnt6_G2 { +private: + mnt6_Fq3 X_, Y_, Z_; +public: +#ifdef PROFILE_OP_COUNTS + static long long add_cnt; + static long long dbl_cnt; +#endif + static std::vector wnaf_window_table; + static std::vector fixed_base_exp_window_table; + static mnt6_G2 G2_zero; + static mnt6_G2 G2_one; + static mnt6_Fq3 twist; + static mnt6_Fq3 coeff_a; + static mnt6_Fq3 coeff_b; + + typedef mnt6_Fq base_field; + typedef mnt6_Fq3 twist_field; + typedef mnt6_Fr scalar_field; + + // using projective coordinates + mnt6_G2(); + mnt6_G2(const mnt6_Fq3& X, const mnt6_Fq3& Y, const mnt6_Fq3& Z) : X_(X), Y_(Y), Z_(Z) {} + + mnt6_Fq3 X() const { return X_; } + mnt6_Fq3 Y() const { return Y_; } + mnt6_Fq3 Z() const { return Z_; } + + static mnt6_Fq3 mul_by_a(const mnt6_Fq3 &elt); + static mnt6_Fq3 mul_by_b(const mnt6_Fq3 &elt); + + void print() const; + void print_coordinates() const; + + void to_affine_coordinates(); + void to_special(); + bool is_special() const; + + bool is_zero() const; + + bool operator==(const mnt6_G2 &other) const; + bool operator!=(const mnt6_G2 &other) const; + + mnt6_G2 operator+(const mnt6_G2 &other) const; + mnt6_G2 operator-() const; + mnt6_G2 operator-(const mnt6_G2 &other) const; + + mnt6_G2 add(const mnt6_G2 &other) const; + mnt6_G2 mixed_add(const mnt6_G2 &other) const; + mnt6_G2 dbl() const; + mnt6_G2 mul_by_q() const; + + bool is_well_formed() const; + + static mnt6_G2 zero(); + static mnt6_G2 one(); + static mnt6_G2 random_element(); + + static size_t size_in_bits() { return twist_field::size_in_bits() + 1; } + static bigint base_field_char() { return base_field::field_char(); } + static bigint order() { return scalar_field::field_char(); } + + friend std::ostream& operator<<(std::ostream &out, const mnt6_G2 &g); + friend std::istream& operator>>(std::istream &in, mnt6_G2 &g); +}; + +template +mnt6_G2 operator*(const bigint &lhs, const mnt6_G2 &rhs) +{ + return scalar_mul(rhs, lhs); +} + +template& modulus_p> +mnt6_G2 operator*(const Fp_model &lhs, const mnt6_G2 &rhs) +{ + return scalar_mul(rhs, lhs.as_bigint()); +} + +template +void batch_to_special_all_non_zeros(std::vector &vec); +template<> +void batch_to_special_all_non_zeros(std::vector &vec); + +} // libsnark + +#endif // MNT6_G2_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/mnt/mnt6/mnt6_init.cpp b/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/mnt/mnt6/mnt6_init.cpp new file mode 100644 index 0000000..715a6be --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/mnt/mnt6/mnt6_init.cpp @@ -0,0 +1,277 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for initializing MNT6. + + See mnt6_init.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include "algebra/curves/mnt/mnt6/mnt6_init.hpp" +#include "algebra/curves/mnt/mnt6/mnt6_g1.hpp" +#include "algebra/curves/mnt/mnt6/mnt6_g2.hpp" + +namespace libsnark { + +//bigint mnt6_modulus_r = mnt46_modulus_B; +//bigint mnt6_modulus_q = mnt46_modulus_A; + +mnt6_Fq3 mnt6_twist; +mnt6_Fq3 mnt6_twist_coeff_a; +mnt6_Fq3 mnt6_twist_coeff_b; +mnt6_Fq mnt6_twist_mul_by_a_c0; +mnt6_Fq mnt6_twist_mul_by_a_c1; +mnt6_Fq mnt6_twist_mul_by_a_c2; +mnt6_Fq mnt6_twist_mul_by_b_c0; +mnt6_Fq mnt6_twist_mul_by_b_c1; +mnt6_Fq mnt6_twist_mul_by_b_c2; +mnt6_Fq mnt6_twist_mul_by_q_X; +mnt6_Fq mnt6_twist_mul_by_q_Y; + +bigint mnt6_ate_loop_count; +bool mnt6_ate_is_loop_count_neg; +bigint<6*mnt6_q_limbs> mnt6_final_exponent; +bigint mnt6_final_exponent_last_chunk_abs_of_w0; +bool mnt6_final_exponent_last_chunk_is_w0_neg; +bigint mnt6_final_exponent_last_chunk_w1; + +void init_mnt6_params() +{ + typedef bigint bigint_r; + typedef bigint bigint_q; + + assert(sizeof(mp_limb_t) == 8 || sizeof(mp_limb_t) == 4); // Montgomery assumes this + + /* parameters for scalar field Fr */ + mnt6_modulus_r = bigint_r("475922286169261325753349249653048451545124879242694725395555128576210262817955800483758081"); + assert(mnt6_Fr::modulus_is_valid()); + if (sizeof(mp_limb_t) == 8) + { + mnt6_Fr::Rsquared = bigint_r("273000478523237720910981655601160860640083126627235719712980612296263966512828033847775776"); + mnt6_Fr::Rcubed = bigint_r("427298980065529822574935274648041073124704261331681436071990730954930769758106792920349077"); + mnt6_Fr::inv = 0xb071a1b67165ffff; + } + if (sizeof(mp_limb_t) == 4) + { + mnt6_Fr::Rsquared = bigint_r("273000478523237720910981655601160860640083126627235719712980612296263966512828033847775776"); + mnt6_Fr::Rcubed = bigint_r("427298980065529822574935274648041073124704261331681436071990730954930769758106792920349077"); + mnt6_Fr::inv = 0x7165ffff; + } + mnt6_Fr::num_bits = 298; + mnt6_Fr::euler = bigint_r("237961143084630662876674624826524225772562439621347362697777564288105131408977900241879040"); + mnt6_Fr::s = 17; + mnt6_Fr::t = bigint_r("3630998887399759870554727551674258816109656366292531779446068791017229177993437198515"); + mnt6_Fr::t_minus_1_over_2 = bigint_r("1815499443699879935277363775837129408054828183146265889723034395508614588996718599257"); + mnt6_Fr::multiplicative_generator = mnt6_Fr("17"); + mnt6_Fr::root_of_unity = mnt6_Fr("264706250571800080758069302369654305530125675521263976034054878017580902343339784464690243"); + mnt6_Fr::nqr = mnt6_Fr("17"); + mnt6_Fr::nqr_to_t = mnt6_Fr("264706250571800080758069302369654305530125675521263976034054878017580902343339784464690243"); + + /* parameters for base field Fq */ + mnt6_modulus_q = bigint_q("475922286169261325753349249653048451545124878552823515553267735739164647307408490559963137"); + assert(mnt6_Fq::modulus_is_valid()); + if (sizeof(mp_limb_t) == 8) + { + mnt6_Fq::Rsquared = bigint_q("163983144722506446826715124368972380525894397127205577781234305496325861831001705438796139"); + mnt6_Fq::Rcubed = bigint_q("207236281459091063710247635236340312578688659363066707916716212805695955118593239854980171"); + mnt6_Fq::inv = 0xbb4334a3ffffffff; + } + if (sizeof(mp_limb_t) == 4) + { + mnt6_Fq::Rsquared = bigint_q("163983144722506446826715124368972380525894397127205577781234305496325861831001705438796139"); + mnt6_Fq::Rcubed = bigint_q("207236281459091063710247635236340312578688659363066707916716212805695955118593239854980171"); + mnt6_Fq::inv = 0xffffffff; + } + mnt6_Fq::num_bits = 298; + mnt6_Fq::euler = bigint_q("237961143084630662876674624826524225772562439276411757776633867869582323653704245279981568"); + mnt6_Fq::s = 34; + mnt6_Fq::t = bigint_q("27702323054502562488973446286577291993024111641153199339359284829066871159442729"); + mnt6_Fq::t_minus_1_over_2 = bigint_q("13851161527251281244486723143288645996512055820576599669679642414533435579721364"); + mnt6_Fq::multiplicative_generator = mnt6_Fq("10"); + mnt6_Fq::root_of_unity = mnt6_Fq("120638817826913173458768829485690099845377008030891618010109772937363554409782252579816313"); + mnt6_Fq::nqr = mnt6_Fq("5"); + mnt6_Fq::nqr_to_t = mnt6_Fq("406220604243090401056429458730298145937262552508985450684842547562990900634752279902740880"); + + /* parameters for twist field Fq3 */ + mnt6_Fq3::euler = bigint<3*mnt6_q_limbs>("53898680178554951715397245154796036139463891589001478629193136369124915637741423690184935056189295242736833704290747216410090671804540908400210778934462129625646263095398323485795557551284190224166851571615834194321908328559167529729507439069424158411618728014749106176"); + mnt6_Fq3::s = 34; + mnt6_Fq3::t = bigint<3*mnt6_q_limbs>("6274632199033507112809136178669989590936327770934612330653836993631547740397674926811006741620285348354004521888069251599964996777072188956687550402067383940523288107407084140669968625447269322370045302856694231080113482726640944570478452261237446033817102203"); + mnt6_Fq3::t_minus_1_over_2 = bigint<3*mnt6_q_limbs>("3137316099516753556404568089334994795468163885467306165326918496815773870198837463405503370810142674177002260944034625799982498388536094478343775201033691970261644053703542070334984312723634661185022651428347115540056741363320472285239226130618723016908551101"); + mnt6_Fq3::non_residue = mnt6_Fq("5"); + mnt6_Fq3::nqr = mnt6_Fq3(mnt6_Fq("5"),mnt6_Fq("0"),mnt6_Fq("0")); + mnt6_Fq3::nqr_to_t = mnt6_Fq3(mnt6_Fq("154361449678783505076984156275977937654331103361174469632346230549735979552469642799720052"),mnt6_Fq("0"),mnt6_Fq("0")); + mnt6_Fq3::Frobenius_coeffs_c1[0] = mnt6_Fq("1"); + mnt6_Fq3::Frobenius_coeffs_c1[1] = mnt6_Fq("471738898967521029133040851318449165997304108729558973770077319830005517129946578866686956"); + mnt6_Fq3::Frobenius_coeffs_c1[2] = mnt6_Fq("4183387201740296620308398334599285547820769823264541783190415909159130177461911693276180"); + mnt6_Fq3::Frobenius_coeffs_c2[0] = mnt6_Fq("1"); + mnt6_Fq3::Frobenius_coeffs_c2[1] = mnt6_Fq("4183387201740296620308398334599285547820769823264541783190415909159130177461911693276180"); + mnt6_Fq3::Frobenius_coeffs_c2[2] = mnt6_Fq("471738898967521029133040851318449165997304108729558973770077319830005517129946578866686956"); + + /* parameters for Fq6 */ + mnt6_Fq6::non_residue = mnt6_Fq("5"); + mnt6_Fq6::Frobenius_coeffs_c1[0] = mnt6_Fq("1"); + mnt6_Fq6::Frobenius_coeffs_c1[1] = mnt6_Fq("471738898967521029133040851318449165997304108729558973770077319830005517129946578866686957"); + mnt6_Fq6::Frobenius_coeffs_c1[2] = mnt6_Fq("471738898967521029133040851318449165997304108729558973770077319830005517129946578866686956"); + mnt6_Fq6::Frobenius_coeffs_c1[3] = mnt6_Fq("475922286169261325753349249653048451545124878552823515553267735739164647307408490559963136"); + mnt6_Fq6::Frobenius_coeffs_c1[4] = mnt6_Fq("4183387201740296620308398334599285547820769823264541783190415909159130177461911693276180"); + mnt6_Fq6::Frobenius_coeffs_c1[5] = mnt6_Fq("4183387201740296620308398334599285547820769823264541783190415909159130177461911693276181"); + mnt6_Fq6::my_Fp2::non_residue = mnt6_Fq3::non_residue; + + /* choice of short Weierstrass curve and its twist */ + mnt6_G1::coeff_a = mnt6_Fq("11"); + mnt6_G1::coeff_b = mnt6_Fq("106700080510851735677967319632585352256454251201367587890185989362936000262606668469523074"); + mnt6_twist = mnt6_Fq3(mnt6_Fq::zero(), mnt6_Fq::one(), mnt6_Fq::zero()); + mnt6_twist_coeff_a = mnt6_Fq3(mnt6_Fq::zero(), mnt6_Fq::zero(), + mnt6_G1::coeff_a); + mnt6_twist_coeff_b = mnt6_Fq3(mnt6_G1::coeff_b * mnt6_Fq3::non_residue, + mnt6_Fq::zero(), mnt6_Fq::zero()); + mnt6_G2::twist = mnt6_twist; + mnt6_G2::coeff_a = mnt6_twist_coeff_a; + mnt6_G2::coeff_b = mnt6_twist_coeff_b; + mnt6_twist_mul_by_a_c0 = mnt6_G1::coeff_a * mnt6_Fq3::non_residue; + mnt6_twist_mul_by_a_c1 = mnt6_G1::coeff_a * mnt6_Fq3::non_residue; + mnt6_twist_mul_by_a_c2 = mnt6_G1::coeff_a; + mnt6_twist_mul_by_b_c0 = mnt6_G1::coeff_b * mnt6_Fq3::non_residue; + mnt6_twist_mul_by_b_c1 = mnt6_G1::coeff_b * mnt6_Fq3::non_residue; + mnt6_twist_mul_by_b_c2 = mnt6_G1::coeff_b * mnt6_Fq3::non_residue; + mnt6_twist_mul_by_q_X = mnt6_Fq("4183387201740296620308398334599285547820769823264541783190415909159130177461911693276180"); + mnt6_twist_mul_by_q_Y = mnt6_Fq("475922286169261325753349249653048451545124878552823515553267735739164647307408490559963136"); + + /* choice of group G1 */ + mnt6_G1::G1_zero = mnt6_G1(mnt6_Fq::zero(), + mnt6_Fq::one(), + mnt6_Fq::zero()); + mnt6_G1::G1_one = mnt6_G1(mnt6_Fq("336685752883082228109289846353937104185698209371404178342968838739115829740084426881123453"), + mnt6_Fq("402596290139780989709332707716568920777622032073762749862342374583908837063963736098549800"), + mnt6_Fq::one()); + + mnt6_G1::wnaf_window_table.resize(0); + mnt6_G1::wnaf_window_table.push_back(11); + mnt6_G1::wnaf_window_table.push_back(24); + mnt6_G1::wnaf_window_table.push_back(60); + mnt6_G1::wnaf_window_table.push_back(127); + + mnt6_G1::fixed_base_exp_window_table.resize(0); + // window 1 is unbeaten in [-inf, 3.96] + mnt6_G1::fixed_base_exp_window_table.push_back(1); + // window 2 is unbeaten in [3.96, 9.67] + mnt6_G1::fixed_base_exp_window_table.push_back(4); + // window 3 is unbeaten in [9.67, 25.13] + mnt6_G1::fixed_base_exp_window_table.push_back(10); + // window 4 is unbeaten in [25.13, 60.31] + mnt6_G1::fixed_base_exp_window_table.push_back(25); + // window 5 is unbeaten in [60.31, 146.07] + mnt6_G1::fixed_base_exp_window_table.push_back(60); + // window 6 is unbeaten in [146.07, 350.09] + mnt6_G1::fixed_base_exp_window_table.push_back(146); + // window 7 is unbeaten in [350.09, 844.54] + mnt6_G1::fixed_base_exp_window_table.push_back(350); + // window 8 is unbeaten in [844.54, 1839.64] + mnt6_G1::fixed_base_exp_window_table.push_back(845); + // window 9 is unbeaten in [1839.64, 3904.26] + mnt6_G1::fixed_base_exp_window_table.push_back(1840); + // window 10 is unbeaten in [3904.26, 11309.42] + mnt6_G1::fixed_base_exp_window_table.push_back(3904); + // window 11 is unbeaten in [11309.42, 24015.57] + mnt6_G1::fixed_base_exp_window_table.push_back(11309); + // window 12 is unbeaten in [24015.57, 72288.57] + mnt6_G1::fixed_base_exp_window_table.push_back(24016); + // window 13 is unbeaten in [72288.57, 138413.22] + mnt6_G1::fixed_base_exp_window_table.push_back(72289); + // window 14 is unbeaten in [138413.22, 156390.30] + mnt6_G1::fixed_base_exp_window_table.push_back(138413); + // window 15 is unbeaten in [156390.30, 562560.50] + mnt6_G1::fixed_base_exp_window_table.push_back(156390); + // window 16 is unbeaten in [562560.50, 1036742.02] + mnt6_G1::fixed_base_exp_window_table.push_back(562560); + // window 17 is unbeaten in [1036742.02, 2053818.86] + mnt6_G1::fixed_base_exp_window_table.push_back(1036742); + // window 18 is unbeaten in [2053818.86, 4370223.95] + mnt6_G1::fixed_base_exp_window_table.push_back(2053819); + // window 19 is unbeaten in [4370223.95, 8215703.81] + mnt6_G1::fixed_base_exp_window_table.push_back(4370224); + // window 20 is unbeaten in [8215703.81, 42682375.43] + mnt6_G1::fixed_base_exp_window_table.push_back(8215704); + // window 21 is never the best + mnt6_G1::fixed_base_exp_window_table.push_back(0); + // window 22 is unbeaten in [42682375.43, inf] + mnt6_G1::fixed_base_exp_window_table.push_back(42682375); + + /* choice of group G2 */ + mnt6_G2::G2_zero = mnt6_G2(mnt6_Fq3::zero(), + mnt6_Fq3::one(), + mnt6_Fq3::zero()); + mnt6_G2::G2_one = mnt6_G2(mnt6_Fq3(mnt6_Fq("421456435772811846256826561593908322288509115489119907560382401870203318738334702321297427"), + mnt6_Fq("103072927438548502463527009961344915021167584706439945404959058962657261178393635706405114"), + mnt6_Fq("143029172143731852627002926324735183809768363301149009204849580478324784395590388826052558")), + mnt6_Fq3(mnt6_Fq("464673596668689463130099227575639512541218133445388869383893594087634649237515554342751377"), + mnt6_Fq("100642907501977375184575075967118071807821117960152743335603284583254620685343989304941678"), + mnt6_Fq("123019855502969896026940545715841181300275180157288044663051565390506010149881373807142903")), + mnt6_Fq3::one()); + + mnt6_G2::wnaf_window_table.resize(0); + mnt6_G2::wnaf_window_table.push_back(5); + mnt6_G2::wnaf_window_table.push_back(15); + mnt6_G2::wnaf_window_table.push_back(39); + mnt6_G2::wnaf_window_table.push_back(109); + + mnt6_G2::fixed_base_exp_window_table.resize(0); + // window 1 is unbeaten in [-inf, 4.25] + mnt6_G2::fixed_base_exp_window_table.push_back(1); + // window 2 is unbeaten in [4.25, 10.22] + mnt6_G2::fixed_base_exp_window_table.push_back(4); + // window 3 is unbeaten in [10.22, 24.85] + mnt6_G2::fixed_base_exp_window_table.push_back(10); + // window 4 is unbeaten in [24.85, 60.06] + mnt6_G2::fixed_base_exp_window_table.push_back(25); + // window 5 is unbeaten in [60.06, 143.61] + mnt6_G2::fixed_base_exp_window_table.push_back(60); + // window 6 is unbeaten in [143.61, 345.66] + mnt6_G2::fixed_base_exp_window_table.push_back(144); + // window 7 is unbeaten in [345.66, 818.56] + mnt6_G2::fixed_base_exp_window_table.push_back(346); + // window 8 is unbeaten in [818.56, 1782.06] + mnt6_G2::fixed_base_exp_window_table.push_back(819); + // window 9 is unbeaten in [1782.06, 4002.45] + mnt6_G2::fixed_base_exp_window_table.push_back(1782); + // window 10 is unbeaten in [4002.45, 10870.18] + mnt6_G2::fixed_base_exp_window_table.push_back(4002); + // window 11 is unbeaten in [10870.18, 18022.51] + mnt6_G2::fixed_base_exp_window_table.push_back(10870); + // window 12 is unbeaten in [18022.51, 43160.74] + mnt6_G2::fixed_base_exp_window_table.push_back(18023); + // window 13 is unbeaten in [43160.74, 149743.32] + mnt6_G2::fixed_base_exp_window_table.push_back(43161); + // window 14 is never the best + mnt6_G2::fixed_base_exp_window_table.push_back(0); + // window 15 is unbeaten in [149743.32, 551844.13] + mnt6_G2::fixed_base_exp_window_table.push_back(149743); + // window 16 is unbeaten in [551844.13, 1041827.91] + mnt6_G2::fixed_base_exp_window_table.push_back(551844); + // window 17 is unbeaten in [1041827.91, 1977371.53] + mnt6_G2::fixed_base_exp_window_table.push_back(1041828); + // window 18 is unbeaten in [1977371.53, 3703619.51] + mnt6_G2::fixed_base_exp_window_table.push_back(1977372); + // window 19 is unbeaten in [3703619.51, 7057236.87] + mnt6_G2::fixed_base_exp_window_table.push_back(3703620); + // window 20 is unbeaten in [7057236.87, 38554491.67] + mnt6_G2::fixed_base_exp_window_table.push_back(7057237); + // window 21 is never the best + mnt6_G2::fixed_base_exp_window_table.push_back(0); + // window 22 is unbeaten in [38554491.67, inf] + mnt6_G2::fixed_base_exp_window_table.push_back(38554492); + + /* pairing parameters */ + mnt6_ate_loop_count = bigint_q("689871209842287392837045615510547309923794944"); + mnt6_ate_is_loop_count_neg = true; + mnt6_final_exponent = bigint<6*mnt6_q_limbs>("24416320138090509697890595414313438768353977489862543935904010715439066975957855922532159264213056712140358746422742237328406558352706591021642230618060502855451264045397444793186876199015256781648746888625527075466063075011307800862173764236311342105211681121426931616843635215852236649271569251468773714424208521977615548771268520882870120900360322044218806712027729351845307690474985502587527753847200130592058098363641559341826790559426614919168"); + mnt6_final_exponent_last_chunk_abs_of_w0 = bigint_q("689871209842287392837045615510547309923794944"); + mnt6_final_exponent_last_chunk_is_w0_neg = true; + mnt6_final_exponent_last_chunk_w1 = bigint_q("1"); +} + +} // libsnark diff --git a/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/mnt/mnt6/mnt6_init.hpp b/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/mnt/mnt6/mnt6_init.hpp new file mode 100644 index 0000000..10cd9da --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/mnt/mnt6/mnt6_init.hpp @@ -0,0 +1,69 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for initializing MNT6. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef MNT6_INIT_HPP_ +#define MNT6_INIT_HPP_ + +#include "algebra/curves/public_params.hpp" +#include "algebra/curves/mnt/mnt46_common.hpp" +#include "algebra/fields/fp.hpp" +#include "algebra/fields/fp3.hpp" +#include "algebra/fields/fp6_2over3.hpp" + +namespace libsnark { + +#define mnt6_modulus_r mnt46_modulus_B +#define mnt6_modulus_q mnt46_modulus_A + +const mp_size_t mnt6_r_bitcount = mnt46_B_bitcount; +const mp_size_t mnt6_q_bitcount = mnt46_A_bitcount; + +const mp_size_t mnt6_r_limbs = mnt46_B_limbs; +const mp_size_t mnt6_q_limbs = mnt46_A_limbs; + +extern bigint mnt6_modulus_r; +extern bigint mnt6_modulus_q; + +typedef Fp_model mnt6_Fr; +typedef Fp_model mnt6_Fq; +typedef Fp3_model mnt6_Fq3; +typedef Fp6_2over3_model mnt6_Fq6; +typedef mnt6_Fq6 mnt6_GT; + +// parameters for twisted short Weierstrass curve E'/Fq3 : y^2 = x^3 + (a * twist^2) * x + (b * twist^3) +extern mnt6_Fq3 mnt6_twist; +extern mnt6_Fq3 mnt6_twist_coeff_a; +extern mnt6_Fq3 mnt6_twist_coeff_b; +extern mnt6_Fq mnt6_twist_mul_by_a_c0; +extern mnt6_Fq mnt6_twist_mul_by_a_c1; +extern mnt6_Fq mnt6_twist_mul_by_a_c2; +extern mnt6_Fq mnt6_twist_mul_by_b_c0; +extern mnt6_Fq mnt6_twist_mul_by_b_c1; +extern mnt6_Fq mnt6_twist_mul_by_b_c2; +extern mnt6_Fq mnt6_twist_mul_by_q_X; +extern mnt6_Fq mnt6_twist_mul_by_q_Y; + +// parameters for pairing +extern bigint mnt6_ate_loop_count; +extern bool mnt6_ate_is_loop_count_neg; +extern bigint<6*mnt6_q_limbs> mnt6_final_exponent; +extern bigint mnt6_final_exponent_last_chunk_abs_of_w0; +extern bool mnt6_final_exponent_last_chunk_is_w0_neg; +extern bigint mnt6_final_exponent_last_chunk_w1; + +void init_mnt6_params(); + +class mnt6_G1; +class mnt6_G2; + +} // libsnark + +#endif // MNT6_INIT_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/mnt/mnt6/mnt6_pairing.cpp b/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/mnt/mnt6/mnt6_pairing.cpp new file mode 100644 index 0000000..41fc2f5 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/mnt/mnt6/mnt6_pairing.cpp @@ -0,0 +1,753 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for pairing operations on MNT6. + + See mnt6_pairing.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include + +#include "algebra/curves/mnt/mnt6/mnt6_pairing.hpp" +#include "algebra/curves/mnt/mnt6/mnt6_init.hpp" +#include "algebra/curves/mnt/mnt6/mnt6_g1.hpp" +#include "algebra/curves/mnt/mnt6/mnt6_g2.hpp" +#include "algebra/scalar_multiplication/wnaf.hpp" +#include "common/profiling.hpp" + +namespace libsnark { + +bool mnt6_ate_G1_precomp::operator==(const mnt6_ate_G1_precomp &other) const +{ + return (this->PX == other.PX && + this->PY == other.PY && + this->PX_twist == other.PX_twist && + this->PY_twist == other.PY_twist); +} + +std::ostream& operator<<(std::ostream &out, const mnt6_ate_G1_precomp &prec_P) +{ + out << prec_P.PX << OUTPUT_SEPARATOR << prec_P.PY << OUTPUT_SEPARATOR << prec_P.PX_twist << OUTPUT_SEPARATOR << prec_P.PY_twist; + + return out; +} + +std::istream& operator>>(std::istream &in, mnt6_ate_G1_precomp &prec_P) +{ + in >> prec_P.PX; + consume_OUTPUT_SEPARATOR(in); + in >> prec_P.PY; + consume_OUTPUT_SEPARATOR(in); + in >> prec_P.PX_twist; + consume_OUTPUT_SEPARATOR(in); + in >> prec_P.PY_twist; + + return in; +} + +bool mnt6_ate_dbl_coeffs::operator==(const mnt6_ate_dbl_coeffs &other) const +{ + return (this->c_H == other.c_H && + this->c_4C == other.c_4C && + this->c_J == other.c_J && + this->c_L == other.c_L); +} + +std::ostream& operator<<(std::ostream &out, const mnt6_ate_dbl_coeffs &dc) +{ + out << dc.c_H << OUTPUT_SEPARATOR << dc.c_4C << OUTPUT_SEPARATOR << dc.c_J << OUTPUT_SEPARATOR << dc.c_L; + return out; +} + +std::istream& operator>>(std::istream &in, mnt6_ate_dbl_coeffs &dc) +{ + in >> dc.c_H; + consume_OUTPUT_SEPARATOR(in); + in >> dc.c_4C; + consume_OUTPUT_SEPARATOR(in); + in >> dc.c_J; + consume_OUTPUT_SEPARATOR(in); + in >> dc.c_L; + + return in; +} + +bool mnt6_ate_add_coeffs::operator==(const mnt6_ate_add_coeffs &other) const +{ + return (this->c_L1 == other.c_L1 && + this->c_RZ == other.c_RZ); +} + +std::ostream& operator<<(std::ostream &out, const mnt6_ate_add_coeffs &ac) +{ + out << ac.c_L1 << OUTPUT_SEPARATOR << ac.c_RZ; + return out; +} + +std::istream& operator>>(std::istream &in, mnt6_ate_add_coeffs &ac) +{ + in >> ac.c_L1; + consume_OUTPUT_SEPARATOR(in); + in >> ac.c_RZ; + + return in; +} + + +bool mnt6_ate_G2_precomp::operator==(const mnt6_ate_G2_precomp &other) const +{ + return (this->QX == other.QX && + this->QY == other.QY && + this->QY2 == other.QY2 && + this->QX_over_twist == other.QX_over_twist && + this->QY_over_twist == other.QY_over_twist && + this->dbl_coeffs == other.dbl_coeffs && + this->add_coeffs == other.add_coeffs); +} + +std::ostream& operator<<(std::ostream& out, const mnt6_ate_G2_precomp &prec_Q) +{ + out << prec_Q.QX << OUTPUT_SEPARATOR + << prec_Q.QY << OUTPUT_SEPARATOR + << prec_Q.QY2 << OUTPUT_SEPARATOR + << prec_Q.QX_over_twist << OUTPUT_SEPARATOR + << prec_Q.QY_over_twist << "\n"; + out << prec_Q.dbl_coeffs.size() << "\n"; + for (const mnt6_ate_dbl_coeffs &dc : prec_Q.dbl_coeffs) + { + out << dc << OUTPUT_NEWLINE; + } + out << prec_Q.add_coeffs.size() << "\n"; + for (const mnt6_ate_add_coeffs &ac : prec_Q.add_coeffs) + { + out << ac << OUTPUT_NEWLINE; + } + + return out; +} + +std::istream& operator>>(std::istream& in, mnt6_ate_G2_precomp &prec_Q) +{ + in >> prec_Q.QX; + consume_OUTPUT_SEPARATOR(in); + in >> prec_Q.QY; + consume_OUTPUT_SEPARATOR(in); + in >> prec_Q.QY2; + consume_OUTPUT_SEPARATOR(in); + in >> prec_Q.QX_over_twist; + consume_OUTPUT_SEPARATOR(in); + in >> prec_Q.QY_over_twist; + consume_newline(in); + + prec_Q.dbl_coeffs.clear(); + size_t dbl_s; + in >> dbl_s; + consume_newline(in); + + prec_Q.dbl_coeffs.reserve(dbl_s); + + for (size_t i = 0; i < dbl_s; ++i) + { + mnt6_ate_dbl_coeffs dc; + in >> dc; + consume_OUTPUT_NEWLINE(in); + prec_Q.dbl_coeffs.emplace_back(dc); + } + + prec_Q.add_coeffs.clear(); + size_t add_s; + in >> add_s; + consume_newline(in); + + prec_Q.add_coeffs.reserve(add_s); + + for (size_t i = 0; i < add_s; ++i) + { + mnt6_ate_add_coeffs ac; + in >> ac; + consume_OUTPUT_NEWLINE(in); + prec_Q.add_coeffs.emplace_back(ac); + } + + return in; +} + +/* final exponentiations */ + +mnt6_Fq6 mnt6_final_exponentiation_last_chunk(const mnt6_Fq6 &elt, const mnt6_Fq6 &elt_inv) +{ + enter_block("Call to mnt6_final_exponentiation_last_chunk"); + const mnt6_Fq6 elt_q = elt.Frobenius_map(1); + mnt6_Fq6 w1_part = elt_q.cyclotomic_exp(mnt6_final_exponent_last_chunk_w1); + mnt6_Fq6 w0_part; + if (mnt6_final_exponent_last_chunk_is_w0_neg) + { + w0_part = elt_inv.cyclotomic_exp(mnt6_final_exponent_last_chunk_abs_of_w0); + } else { + w0_part = elt.cyclotomic_exp(mnt6_final_exponent_last_chunk_abs_of_w0); + } + mnt6_Fq6 result = w1_part * w0_part; + leave_block("Call to mnt6_final_exponentiation_last_chunk"); + + return result; +} + +mnt6_Fq6 mnt6_final_exponentiation_first_chunk(const mnt6_Fq6 &elt, const mnt6_Fq6 &elt_inv) +{ + enter_block("Call to mnt6_final_exponentiation_first_chunk"); + + /* (q^3-1)*(q+1) */ + + /* elt_q3 = elt^(q^3) */ + const mnt6_Fq6 elt_q3 = elt.Frobenius_map(3); + /* elt_q3_over_elt = elt^(q^3-1) */ + const mnt6_Fq6 elt_q3_over_elt = elt_q3 * elt_inv; + /* alpha = elt^((q^3-1) * q) */ + const mnt6_Fq6 alpha = elt_q3_over_elt.Frobenius_map(1); + /* beta = elt^((q^3-1)*(q+1) */ + const mnt6_Fq6 beta = alpha * elt_q3_over_elt; + leave_block("Call to mnt6_final_exponentiation_first_chunk"); + return beta; +} + +mnt6_GT mnt6_final_exponentiation(const mnt6_Fq6 &elt) +{ + enter_block("Call to mnt6_final_exponentiation"); + const mnt6_Fq6 elt_inv = elt.inverse(); + const mnt6_Fq6 elt_to_first_chunk = mnt6_final_exponentiation_first_chunk(elt, elt_inv); + const mnt6_Fq6 elt_inv_to_first_chunk = mnt6_final_exponentiation_first_chunk(elt_inv, elt); + mnt6_GT result = mnt6_final_exponentiation_last_chunk(elt_to_first_chunk, elt_inv_to_first_chunk); + leave_block("Call to mnt6_final_exponentiation"); + + return result; +} + +/* affine ate miller loop */ + +mnt6_affine_ate_G1_precomputation mnt6_affine_ate_precompute_G1(const mnt6_G1& P) +{ + enter_block("Call to mnt6_affine_ate_precompute_G1"); + + mnt6_G1 Pcopy = P; + Pcopy.to_affine_coordinates(); + + mnt6_affine_ate_G1_precomputation result; + result.PX = Pcopy.X(); + result.PY = Pcopy.Y(); + result.PY_twist_squared = Pcopy.Y() * mnt6_twist.squared(); + + leave_block("Call to mnt6_affine_ate_precompute_G1"); + return result; +} + +mnt6_affine_ate_G2_precomputation mnt6_affine_ate_precompute_G2(const mnt6_G2& Q) +{ + enter_block("Call to mnt6_affine_ate_precompute_G2"); + + mnt6_G2 Qcopy(Q); + Qcopy.to_affine_coordinates(); + + mnt6_affine_ate_G2_precomputation result; + result.QX = Qcopy.X(); + result.QY = Qcopy.Y(); + + mnt6_Fq3 RX = Qcopy.X(); + mnt6_Fq3 RY = Qcopy.Y(); + + const bigint &loop_count = mnt6_ate_loop_count; + bool found_nonzero = false; + + std::vector NAF = find_wnaf(1, loop_count); + for (long i = NAF.size() - 1; i >= 0; --i) + { + if (!found_nonzero) + { + /* this skips the MSB itself */ + found_nonzero |= (NAF[i] != 0); + continue; + } + + mnt6_affine_ate_coeffs c; + c.old_RX = RX; + c.old_RY = RY; + mnt6_Fq3 old_RX_2 = c.old_RX.squared(); + c.gamma = (old_RX_2 + old_RX_2 + old_RX_2 + mnt6_twist_coeff_a) * (c.old_RY + c.old_RY).inverse(); + c.gamma_twist = c.gamma * mnt6_twist; + c.gamma_X = c.gamma * c.old_RX; + result.coeffs.push_back(c); + + RX = c.gamma.squared() - (c.old_RX+c.old_RX); + RY = c.gamma * (c.old_RX - RX) - c.old_RY; + + if (NAF[i] != 0) + { + mnt6_affine_ate_coeffs c; + c.old_RX = RX; + c.old_RY = RY; + if (NAF[i] > 0) + { + c.gamma = (c.old_RY - result.QY) * (c.old_RX - result.QX).inverse(); + } + else + { + c.gamma = (c.old_RY + result.QY) * (c.old_RX - result.QX).inverse(); + } + c.gamma_twist = c.gamma * mnt6_twist; + c.gamma_X = c.gamma * result.QX; + result.coeffs.push_back(c); + + RX = c.gamma.squared() - (c.old_RX+result.QX); + RY = c.gamma * (c.old_RX - RX) - c.old_RY; + } + } + + /* TODO: maybe handle neg + if (mnt6_ate_is_loop_count_neg) + { + mnt6_ate_add_coeffs ac; + mnt6_affine_ate_dbl_coeffs c; + c.old_RX = RX; + c.old_RY = -RY; + old_RX_2 = c.old_RY.squared(); + c.gamma = (old_RX_2 + old_RX_2 + old_RX_2 + mnt6_coeff_a) * (c.old_RY + c.old_RY).inverse(); + c.gamma_twist = c.gamma * mnt6_twist; + c.gamma_X = c.gamma * c.old_RX; + result.coeffs.push_back(c); + } + */ + + leave_block("Call to mnt6_affine_ate_precompute_G2"); + return result; +} + +mnt6_Fq6 mnt6_affine_ate_miller_loop(const mnt6_affine_ate_G1_precomputation &prec_P, + const mnt6_affine_ate_G2_precomputation &prec_Q) +{ + enter_block("Call to mnt6_affine_ate_miller_loop"); + + mnt6_Fq6 f = mnt6_Fq6::one(); + + const bigint &loop_count = mnt6_ate_loop_count; + bool found_nonzero = false; + size_t idx = 0; + + std::vector NAF = find_wnaf(1, loop_count); + for (long i = NAF.size() - 1; i >= 0; --i) + { + if (!found_nonzero) + { + /* this skips the MSB itself */ + found_nonzero |= (NAF[i] != 0); + continue; + } + + /* code below gets executed for all bits (EXCEPT the MSB itself) of + mnt6_param_p (skipping leading zeros) in MSB to LSB + order */ + mnt6_affine_ate_coeffs c = prec_Q.coeffs[idx++]; + + mnt6_Fq6 g_RR_at_P = mnt6_Fq6(prec_P.PY_twist_squared, + - prec_P.PX * c.gamma_twist + c.gamma_X - c.old_RY); + f = f.squared().mul_by_2345(g_RR_at_P); + + if (NAF[i] != 0) + { + mnt6_affine_ate_coeffs c = prec_Q.coeffs[idx++]; + mnt6_Fq6 g_RQ_at_P; + if (NAF[i] > 0) + { + g_RQ_at_P = mnt6_Fq6(prec_P.PY_twist_squared, + - prec_P.PX * c.gamma_twist + c.gamma_X - prec_Q.QY); + } + else + { + g_RQ_at_P = mnt6_Fq6(prec_P.PY_twist_squared, + - prec_P.PX * c.gamma_twist + c.gamma_X + prec_Q.QY); + } + f = f.mul_by_2345(g_RQ_at_P); + } + + } + + /* TODO: maybe handle neg + if (mnt6_ate_is_loop_count_neg) + { + // TODO: + mnt6_affine_ate_coeffs ac = prec_Q.coeffs[idx++]; + mnt6_Fq6 g_RnegR_at_P = mnt6_Fq6(prec_P.PY_twist_squared, + - prec_P.PX * c.gamma_twist + c.gamma_X - c.old_RY); + f = (f * g_RnegR_at_P).inverse(); + } + */ + + leave_block("Call to mnt6_affine_ate_miller_loop"); + + return f; +} + +/* ate pairing */ + +struct extended_mnt6_G2_projective { + mnt6_Fq3 X; + mnt6_Fq3 Y; + mnt6_Fq3 Z; + mnt6_Fq3 T; + + void print() const + { + printf("extended mnt6_G2 projective X/Y/Z/T:\n"); + X.print(); + Y.print(); + Z.print(); + T.print(); + } + + void test_invariant() const + { + assert(T == Z.squared()); + } +}; + +void doubling_step_for_flipped_miller_loop(extended_mnt6_G2_projective ¤t, + mnt6_ate_dbl_coeffs &dc) +{ + const mnt6_Fq3 X = current.X, Y = current.Y, Z = current.Z, T = current.T; + + const mnt6_Fq3 A = T.squared(); // A = T1^2 + const mnt6_Fq3 B = X.squared(); // B = X1^2 + const mnt6_Fq3 C = Y.squared(); // C = Y1^2 + const mnt6_Fq3 D = C.squared(); // D = C^2 + const mnt6_Fq3 E = (X+C).squared() - B - D; // E = (X1+C)^2-B-D + const mnt6_Fq3 F = (B+B+B) + mnt6_twist_coeff_a * A; // F = 3*B + a *A + const mnt6_Fq3 G = F.squared(); // G = F^2 + + current.X = -(E+E+E+E) + G; // X3 = -4*E+G + current.Y = -mnt6_Fq("8")*D + F*(E+E-current.X); // Y3 = -8*D+F*(2*E-X3) + current.Z = (Y+Z).squared() - C - Z.squared(); // Z3 = (Y1+Z1)^2-C-Z1^2 + current.T = current.Z.squared(); // T3 = Z3^2 + + dc.c_H = (current.Z + T).squared() - current.T - A; // H = (Z3+T1)^2-T3-A + dc.c_4C = C+C+C+C; // fourC = 4*C + dc.c_J = (F+T).squared() - G - A; // J = (F+T1)^2-G-A + dc.c_L = (F+X).squared() - G - B; // L = (F+X1)^2-G-B + +#ifdef DEBUG + current.test_invariant(); +#endif +} + +void mixed_addition_step_for_flipped_miller_loop(const mnt6_Fq3 base_X, const mnt6_Fq3 base_Y, const mnt6_Fq3 base_Y_squared, + extended_mnt6_G2_projective ¤t, + mnt6_ate_add_coeffs &ac) +{ + const mnt6_Fq3 X1 = current.X, Y1 = current.Y, Z1 = current.Z, T1 = current.T; + const mnt6_Fq3 &x2 = base_X, &y2 = base_Y, &y2_squared = base_Y_squared; + + const mnt6_Fq3 B = x2 * T1; // B = x2 * T1 + const mnt6_Fq3 D = ((y2 + Z1).squared() - y2_squared - T1) * T1; // D = ((y2 + Z1)^2 - y2squared - T1) * T1 + const mnt6_Fq3 H = B - X1; // H = B - X1 + const mnt6_Fq3 I = H.squared(); // I = H^2 + const mnt6_Fq3 E = I + I + I + I; // E = 4*I + const mnt6_Fq3 J = H * E; // J = H * E + const mnt6_Fq3 V = X1 * E; // V = X1 * E + const mnt6_Fq3 L1 = D - (Y1 + Y1); // L1 = D - 2 * Y1 + + current.X = L1.squared() - J - (V+V); // X3 = L1^2 - J - 2*V + current.Y = L1 * (V-current.X) - (Y1+Y1) * J; // Y3 = L1 * (V-X3) - 2*Y1 * J + current.Z = (Z1+H).squared() - T1 - I; // Z3 = (Z1 + H)^2 - T1 - I + current.T = current.Z.squared(); // T3 = Z3^2 + + ac.c_L1 = L1; + ac.c_RZ = current.Z; +#ifdef DEBUG + current.test_invariant(); +#endif +} + +mnt6_ate_G1_precomp mnt6_ate_precompute_G1(const mnt6_G1& P) +{ + enter_block("Call to mnt6_ate_precompute_G1"); + + mnt6_G1 Pcopy = P; + Pcopy.to_affine_coordinates(); + + mnt6_ate_G1_precomp result; + result.PX = Pcopy.X(); + result.PY = Pcopy.Y(); + result.PX_twist = Pcopy.X() * mnt6_twist; + result.PY_twist = Pcopy.Y() * mnt6_twist; + + leave_block("Call to mnt6_ate_precompute_G1"); + return result; +} + +mnt6_ate_G2_precomp mnt6_ate_precompute_G2(const mnt6_G2& Q) +{ + enter_block("Call to mnt6_ate_precompute_G2"); + + mnt6_G2 Qcopy(Q); + Qcopy.to_affine_coordinates(); + + mnt6_Fq3 mnt6_twist_inv = mnt6_twist.inverse(); // could add to global params if needed + + mnt6_ate_G2_precomp result; + result.QX = Qcopy.X(); + result.QY = Qcopy.Y(); + result.QY2 = Qcopy.Y().squared(); + result.QX_over_twist = Qcopy.X() * mnt6_twist_inv; + result.QY_over_twist = Qcopy.Y() * mnt6_twist_inv; + + extended_mnt6_G2_projective R; + R.X = Qcopy.X(); + R.Y = Qcopy.Y(); + R.Z = mnt6_Fq3::one(); + R.T = mnt6_Fq3::one(); + + const bigint &loop_count = mnt6_ate_loop_count; + bool found_one = false; + for (long i = loop_count.max_bits() - 1; i >= 0; --i) + { + const bool bit = loop_count.test_bit(i); + + if (!found_one) + { + /* this skips the MSB itself */ + found_one |= bit; + continue; + } + + mnt6_ate_dbl_coeffs dc; + doubling_step_for_flipped_miller_loop(R, dc); + result.dbl_coeffs.push_back(dc); + + if (bit) + { + mnt6_ate_add_coeffs ac; + mixed_addition_step_for_flipped_miller_loop(result.QX, result.QY, result.QY2, R, ac); + result.add_coeffs.push_back(ac); + } + } + + if (mnt6_ate_is_loop_count_neg) + { + mnt6_Fq3 RZ_inv = R.Z.inverse(); + mnt6_Fq3 RZ2_inv = RZ_inv.squared(); + mnt6_Fq3 RZ3_inv = RZ2_inv * RZ_inv; + mnt6_Fq3 minus_R_affine_X = R.X * RZ2_inv; + mnt6_Fq3 minus_R_affine_Y = - R.Y * RZ3_inv; + mnt6_Fq3 minus_R_affine_Y2 = minus_R_affine_Y.squared(); + mnt6_ate_add_coeffs ac; + mixed_addition_step_for_flipped_miller_loop(minus_R_affine_X, minus_R_affine_Y, minus_R_affine_Y2, R, ac); + result.add_coeffs.push_back(ac); + } + + leave_block("Call to mnt6_ate_precompute_G2"); + return result; +} + +mnt6_Fq6 mnt6_ate_miller_loop(const mnt6_ate_G1_precomp &prec_P, + const mnt6_ate_G2_precomp &prec_Q) +{ + enter_block("Call to mnt6_ate_miller_loop"); + + mnt6_Fq3 L1_coeff = mnt6_Fq3(prec_P.PX, mnt6_Fq::zero(), mnt6_Fq::zero()) - prec_Q.QX_over_twist; + + mnt6_Fq6 f = mnt6_Fq6::one(); + + bool found_one = false; + size_t dbl_idx = 0; + size_t add_idx = 0; + + const bigint &loop_count = mnt6_ate_loop_count; + + for (long i = loop_count.max_bits() - 1; i >= 0; --i) + { + const bool bit = loop_count.test_bit(i); + + if (!found_one) + { + /* this skips the MSB itself */ + found_one |= bit; + continue; + } + + /* code below gets executed for all bits (EXCEPT the MSB itself) of + mnt6_param_p (skipping leading zeros) in MSB to LSB + order */ + mnt6_ate_dbl_coeffs dc = prec_Q.dbl_coeffs[dbl_idx++]; + + mnt6_Fq6 g_RR_at_P = mnt6_Fq6(- dc.c_4C - dc.c_J * prec_P.PX_twist + dc.c_L, + dc.c_H * prec_P.PY_twist); + f = f.squared() * g_RR_at_P; + + if (bit) + { + mnt6_ate_add_coeffs ac = prec_Q.add_coeffs[add_idx++]; + mnt6_Fq6 g_RQ_at_P = mnt6_Fq6(ac.c_RZ * prec_P.PY_twist, + -(prec_Q.QY_over_twist * ac.c_RZ + L1_coeff * ac.c_L1)); + f = f * g_RQ_at_P; + } + + } + + if (mnt6_ate_is_loop_count_neg) + { + mnt6_ate_add_coeffs ac = prec_Q.add_coeffs[add_idx++]; + mnt6_Fq6 g_RnegR_at_P = mnt6_Fq6(ac.c_RZ * prec_P.PY_twist, + -(prec_Q.QY_over_twist * ac.c_RZ + L1_coeff * ac.c_L1)); + f = (f * g_RnegR_at_P).inverse(); + } + + leave_block("Call to mnt6_ate_miller_loop"); + + return f; +} + +mnt6_Fq6 mnt6_ate_double_miller_loop(const mnt6_ate_G1_precomp &prec_P1, + const mnt6_ate_G2_precomp &prec_Q1, + const mnt6_ate_G1_precomp &prec_P2, + const mnt6_ate_G2_precomp &prec_Q2) +{ + enter_block("Call to mnt6_ate_double_miller_loop"); + + mnt6_Fq3 L1_coeff1 = mnt6_Fq3(prec_P1.PX, mnt6_Fq::zero(), mnt6_Fq::zero()) - prec_Q1.QX_over_twist; + mnt6_Fq3 L1_coeff2 = mnt6_Fq3(prec_P2.PX, mnt6_Fq::zero(), mnt6_Fq::zero()) - prec_Q2.QX_over_twist; + + mnt6_Fq6 f = mnt6_Fq6::one(); + + bool found_one = false; + size_t dbl_idx = 0; + size_t add_idx = 0; + + const bigint &loop_count = mnt6_ate_loop_count; + + for (long i = loop_count.max_bits() - 1; i >= 0; --i) + { + const bool bit = loop_count.test_bit(i); + + if (!found_one) + { + /* this skips the MSB itself */ + found_one |= bit; + continue; + } + + /* code below gets executed for all bits (EXCEPT the MSB itself) of + mnt6_param_p (skipping leading zeros) in MSB to LSB + order */ + mnt6_ate_dbl_coeffs dc1 = prec_Q1.dbl_coeffs[dbl_idx]; + mnt6_ate_dbl_coeffs dc2 = prec_Q2.dbl_coeffs[dbl_idx]; + ++dbl_idx; + + mnt6_Fq6 g_RR_at_P1 = mnt6_Fq6(- dc1.c_4C - dc1.c_J * prec_P1.PX_twist + dc1.c_L, + dc1.c_H * prec_P1.PY_twist); + + mnt6_Fq6 g_RR_at_P2 = mnt6_Fq6(- dc2.c_4C - dc2.c_J * prec_P2.PX_twist + dc2.c_L, + dc2.c_H * prec_P2.PY_twist); + + f = f.squared() * g_RR_at_P1 * g_RR_at_P2; + + if (bit) + { + mnt6_ate_add_coeffs ac1 = prec_Q1.add_coeffs[add_idx]; + mnt6_ate_add_coeffs ac2 = prec_Q2.add_coeffs[add_idx]; + ++add_idx; + + mnt6_Fq6 g_RQ_at_P1 = mnt6_Fq6(ac1.c_RZ * prec_P1.PY_twist, + -(prec_Q1.QY_over_twist * ac1.c_RZ + L1_coeff1 * ac1.c_L1)); + mnt6_Fq6 g_RQ_at_P2 = mnt6_Fq6(ac2.c_RZ * prec_P2.PY_twist, + -(prec_Q2.QY_over_twist * ac2.c_RZ + L1_coeff2 * ac2.c_L1)); + + f = f * g_RQ_at_P1 * g_RQ_at_P2; + } + } + + if (mnt6_ate_is_loop_count_neg) + { + mnt6_ate_add_coeffs ac1 = prec_Q1.add_coeffs[add_idx]; + mnt6_ate_add_coeffs ac2 = prec_Q2.add_coeffs[add_idx]; + ++add_idx; + mnt6_Fq6 g_RnegR_at_P1 = mnt6_Fq6(ac1.c_RZ * prec_P1.PY_twist, + -(prec_Q1.QY_over_twist * ac1.c_RZ + L1_coeff1 * ac1.c_L1)); + mnt6_Fq6 g_RnegR_at_P2 = mnt6_Fq6(ac2.c_RZ * prec_P2.PY_twist, + -(prec_Q2.QY_over_twist * ac2.c_RZ + L1_coeff2 * ac2.c_L1)); + + f = (f * g_RnegR_at_P1 * g_RnegR_at_P2).inverse(); + } + + leave_block("Call to mnt6_ate_double_miller_loop"); + + return f; +} + +mnt6_Fq6 mnt6_ate_pairing(const mnt6_G1& P, const mnt6_G2 &Q) +{ + enter_block("Call to mnt6_ate_pairing"); + mnt6_ate_G1_precomp prec_P = mnt6_ate_precompute_G1(P); + mnt6_ate_G2_precomp prec_Q = mnt6_ate_precompute_G2(Q); + mnt6_Fq6 result = mnt6_ate_miller_loop(prec_P, prec_Q); + leave_block("Call to mnt6_ate_pairing"); + return result; +} + +mnt6_GT mnt6_ate_reduced_pairing(const mnt6_G1 &P, const mnt6_G2 &Q) +{ + enter_block("Call to mnt6_ate_reduced_pairing"); + const mnt6_Fq6 f = mnt6_ate_pairing(P, Q); + const mnt6_GT result = mnt6_final_exponentiation(f); + leave_block("Call to mnt6_ate_reduced_pairing"); + return result; +} + +mnt6_G1_precomp mnt6_precompute_G1(const mnt6_G1& P) +{ + return mnt6_ate_precompute_G1(P); +} + +mnt6_G2_precomp mnt6_precompute_G2(const mnt6_G2& Q) +{ + return mnt6_ate_precompute_G2(Q); +} + +mnt6_Fq6 mnt6_miller_loop(const mnt6_G1_precomp &prec_P, + const mnt6_G2_precomp &prec_Q) +{ + return mnt6_ate_miller_loop(prec_P, prec_Q); +} + +mnt6_Fq6 mnt6_double_miller_loop(const mnt6_G1_precomp &prec_P1, + const mnt6_G2_precomp &prec_Q1, + const mnt6_G1_precomp &prec_P2, + const mnt6_G2_precomp &prec_Q2) +{ + return mnt6_ate_double_miller_loop(prec_P1, prec_Q1, prec_P2, prec_Q2); +} + +mnt6_Fq6 mnt6_pairing(const mnt6_G1& P, + const mnt6_G2 &Q) +{ + return mnt6_ate_pairing(P, Q); +} + +mnt6_GT mnt6_reduced_pairing(const mnt6_G1 &P, + const mnt6_G2 &Q) +{ + return mnt6_ate_reduced_pairing(P, Q); +} + +mnt6_GT mnt6_affine_reduced_pairing(const mnt6_G1 &P, + const mnt6_G2 &Q) +{ + const mnt6_affine_ate_G1_precomputation prec_P = mnt6_affine_ate_precompute_G1(P); + const mnt6_affine_ate_G2_precomputation prec_Q = mnt6_affine_ate_precompute_G2(Q); + const mnt6_Fq6 f = mnt6_affine_ate_miller_loop(prec_P, prec_Q); + const mnt6_GT result = mnt6_final_exponentiation(f); + return result; +} + +} // libsnark diff --git a/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/mnt/mnt6/mnt6_pairing.hpp b/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/mnt/mnt6/mnt6_pairing.hpp new file mode 100644 index 0000000..f5c2117 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/mnt/mnt6/mnt6_pairing.hpp @@ -0,0 +1,148 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for pairing operations on MNT6. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef MNT6_PAIRING_HPP_ +#define MNT6_PAIRING_HPP_ + +#include + +#include "algebra/curves/mnt/mnt6/mnt6_init.hpp" + +namespace libsnark { + +/* final exponentiation */ + +mnt6_Fq6 mnt6_final_exponentiation_last_chunk(const mnt6_Fq6 &elt, + const mnt6_Fq6 &elt_inv); +mnt6_Fq6 mnt6_final_exponentiation_first_chunk(const mnt6_Fq6 &elt, + const mnt6_Fq6 &elt_inv); +mnt6_GT mnt6_final_exponentiation(const mnt6_Fq6 &elt); + +/* affine ate miller loop */ + +struct mnt6_affine_ate_G1_precomputation { + mnt6_Fq PX; + mnt6_Fq PY; + mnt6_Fq3 PY_twist_squared; +}; + +struct mnt6_affine_ate_coeffs { + // TODO: trim (not all of them are needed) + mnt6_Fq3 old_RX; + mnt6_Fq3 old_RY; + mnt6_Fq3 gamma; + mnt6_Fq3 gamma_twist; + mnt6_Fq3 gamma_X; +}; + +struct mnt6_affine_ate_G2_precomputation { + mnt6_Fq3 QX; + mnt6_Fq3 QY; + std::vector coeffs; +}; + +mnt6_affine_ate_G1_precomputation mnt6_affine_ate_precompute_G1(const mnt6_G1& P); +mnt6_affine_ate_G2_precomputation mnt6_affine_ate_precompute_G2(const mnt6_G2& Q); + +mnt6_Fq6 mnt6_affine_ate_miller_loop(const mnt6_affine_ate_G1_precomputation &prec_P, + const mnt6_affine_ate_G2_precomputation &prec_Q); + +/* ate pairing */ + +struct mnt6_ate_G1_precomp { + mnt6_Fq PX; + mnt6_Fq PY; + mnt6_Fq3 PX_twist; + mnt6_Fq3 PY_twist; + + bool operator==(const mnt6_ate_G1_precomp &other) const; + friend std::ostream& operator<<(std::ostream &out, const mnt6_ate_G1_precomp &prec_P); + friend std::istream& operator>>(std::istream &in, mnt6_ate_G1_precomp &prec_P); +}; + +struct mnt6_ate_dbl_coeffs { + mnt6_Fq3 c_H; + mnt6_Fq3 c_4C; + mnt6_Fq3 c_J; + mnt6_Fq3 c_L; + + bool operator==(const mnt6_ate_dbl_coeffs &other) const; + friend std::ostream& operator<<(std::ostream &out, const mnt6_ate_dbl_coeffs &dc); + friend std::istream& operator>>(std::istream &in, mnt6_ate_dbl_coeffs &dc); +}; + +struct mnt6_ate_add_coeffs { + mnt6_Fq3 c_L1; + mnt6_Fq3 c_RZ; + + bool operator==(const mnt6_ate_add_coeffs &other) const; + friend std::ostream& operator<<(std::ostream &out, const mnt6_ate_add_coeffs &dc); + friend std::istream& operator>>(std::istream &in, mnt6_ate_add_coeffs &dc); +}; + +struct mnt6_ate_G2_precomp { + mnt6_Fq3 QX; + mnt6_Fq3 QY; + mnt6_Fq3 QY2; + mnt6_Fq3 QX_over_twist; + mnt6_Fq3 QY_over_twist; + std::vector dbl_coeffs; + std::vector add_coeffs; + + bool operator==(const mnt6_ate_G2_precomp &other) const; + friend std::ostream& operator<<(std::ostream &out, const mnt6_ate_G2_precomp &prec_Q); + friend std::istream& operator>>(std::istream &in, mnt6_ate_G2_precomp &prec_Q); +}; + +mnt6_ate_G1_precomp mnt6_ate_precompute_G1(const mnt6_G1& P); +mnt6_ate_G2_precomp mnt6_ate_precompute_G2(const mnt6_G2& Q); + +mnt6_Fq6 mnt6_ate_miller_loop(const mnt6_ate_G1_precomp &prec_P, + const mnt6_ate_G2_precomp &prec_Q); +mnt6_Fq6 mnt6_ate_double_miller_loop(const mnt6_ate_G1_precomp &prec_P1, + const mnt6_ate_G2_precomp &prec_Q1, + const mnt6_ate_G1_precomp &prec_P2, + const mnt6_ate_G2_precomp &prec_Q2); + +mnt6_Fq6 mnt6_ate_pairing(const mnt6_G1& P, + const mnt6_G2 &Q); +mnt6_GT mnt6_ate_reduced_pairing(const mnt6_G1 &P, + const mnt6_G2 &Q); + +/* choice of pairing */ + +typedef mnt6_ate_G1_precomp mnt6_G1_precomp; +typedef mnt6_ate_G2_precomp mnt6_G2_precomp; + +mnt6_G1_precomp mnt6_precompute_G1(const mnt6_G1& P); + +mnt6_G2_precomp mnt6_precompute_G2(const mnt6_G2& Q); + +mnt6_Fq6 mnt6_miller_loop(const mnt6_G1_precomp &prec_P, + const mnt6_G2_precomp &prec_Q); + +mnt6_Fq6 mnt6_double_miller_loop(const mnt6_G1_precomp &prec_P1, + const mnt6_G2_precomp &prec_Q1, + const mnt6_G1_precomp &prec_P2, + const mnt6_G2_precomp &prec_Q2); + +mnt6_Fq6 mnt6_pairing(const mnt6_G1& P, + const mnt6_G2 &Q); + +mnt6_GT mnt6_reduced_pairing(const mnt6_G1 &P, + const mnt6_G2 &Q); + +mnt6_GT mnt6_affine_reduced_pairing(const mnt6_G1 &P, + const mnt6_G2 &Q); + +} // libsnark + +#endif // MNT6_PAIRING_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/mnt/mnt6/mnt6_pp.cpp b/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/mnt/mnt6/mnt6_pp.cpp new file mode 100644 index 0000000..9983d50 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/mnt/mnt6/mnt6_pp.cpp @@ -0,0 +1,106 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for public parameters of MNT6. + + See mnt6_pp.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include "algebra/curves/mnt/mnt6/mnt6_pp.hpp" + +namespace libsnark { + +void mnt6_pp::init_public_params() +{ + init_mnt6_params(); +} + +mnt6_GT mnt6_pp::final_exponentiation(const mnt6_Fq6 &elt) +{ + return mnt6_final_exponentiation(elt); +} + +mnt6_G1_precomp mnt6_pp::precompute_G1(const mnt6_G1 &P) +{ + return mnt6_precompute_G1(P); +} + +mnt6_G2_precomp mnt6_pp::precompute_G2(const mnt6_G2 &Q) +{ + return mnt6_precompute_G2(Q); +} + + +mnt6_Fq6 mnt6_pp::miller_loop(const mnt6_G1_precomp &prec_P, + const mnt6_G2_precomp &prec_Q) +{ + return mnt6_miller_loop(prec_P, prec_Q); +} + +mnt6_affine_ate_G1_precomputation mnt6_pp::affine_ate_precompute_G1(const mnt6_G1 &P) +{ + return mnt6_affine_ate_precompute_G1(P); +} + +mnt6_affine_ate_G2_precomputation mnt6_pp::affine_ate_precompute_G2(const mnt6_G2 &Q) +{ + return mnt6_affine_ate_precompute_G2(Q); +} + +mnt6_Fq6 mnt6_pp::affine_ate_miller_loop(const mnt6_affine_ate_G1_precomputation &prec_P, + const mnt6_affine_ate_G2_precomputation &prec_Q) +{ + return mnt6_affine_ate_miller_loop(prec_P, prec_Q); +} + +mnt6_Fq6 mnt6_pp::double_miller_loop(const mnt6_G1_precomp &prec_P1, + const mnt6_G2_precomp &prec_Q1, + const mnt6_G1_precomp &prec_P2, + const mnt6_G2_precomp &prec_Q2) +{ + return mnt6_double_miller_loop(prec_P1, prec_Q1, prec_P2, prec_Q2); +} + +mnt6_Fq6 mnt6_pp::affine_ate_e_over_e_miller_loop(const mnt6_affine_ate_G1_precomputation &prec_P1, + const mnt6_affine_ate_G2_precomputation &prec_Q1, + const mnt6_affine_ate_G1_precomputation &prec_P2, + const mnt6_affine_ate_G2_precomputation &prec_Q2) +{ + return mnt6_affine_ate_miller_loop(prec_P1, prec_Q1) * mnt6_affine_ate_miller_loop(prec_P2, prec_Q2).unitary_inverse(); +} + +mnt6_Fq6 mnt6_pp::affine_ate_e_times_e_over_e_miller_loop(const mnt6_affine_ate_G1_precomputation &prec_P1, + const mnt6_affine_ate_G2_precomputation &prec_Q1, + const mnt6_affine_ate_G1_precomputation &prec_P2, + const mnt6_affine_ate_G2_precomputation &prec_Q2, + const mnt6_affine_ate_G1_precomputation &prec_P3, + const mnt6_affine_ate_G2_precomputation &prec_Q3) +{ + return ((mnt6_affine_ate_miller_loop(prec_P1, prec_Q1) * mnt6_affine_ate_miller_loop(prec_P2, prec_Q2)) * + mnt6_affine_ate_miller_loop(prec_P3, prec_Q3).unitary_inverse()); +} + +mnt6_Fq6 mnt6_pp::pairing(const mnt6_G1 &P, + const mnt6_G2 &Q) +{ + return mnt6_pairing(P, Q); +} + +mnt6_Fq6 mnt6_pp::reduced_pairing(const mnt6_G1 &P, + const mnt6_G2 &Q) +{ + return mnt6_reduced_pairing(P, Q); +} + +mnt6_Fq6 mnt6_pp::affine_reduced_pairing(const mnt6_G1 &P, + const mnt6_G2 &Q) +{ + return mnt6_affine_reduced_pairing(P, Q); +} + +} // libsnark diff --git a/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/mnt/mnt6/mnt6_pp.hpp b/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/mnt/mnt6/mnt6_pp.hpp new file mode 100644 index 0000000..bbe05a4 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/mnt/mnt6/mnt6_pp.hpp @@ -0,0 +1,75 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for public parameters of MNT6. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef MNT6_PP_HPP_ +#define MNT6_PP_HPP_ + +#include "algebra/curves/public_params.hpp" +#include "algebra/curves/mnt/mnt6/mnt6_init.hpp" +#include "algebra/curves/mnt/mnt6/mnt6_g1.hpp" +#include "algebra/curves/mnt/mnt6/mnt6_g2.hpp" +#include "algebra/curves/mnt/mnt6/mnt6_pairing.hpp" + +namespace libsnark { + +class mnt6_pp { +public: + typedef mnt6_Fr Fp_type; + typedef mnt6_G1 G1_type; + typedef mnt6_G2 G2_type; + typedef mnt6_affine_ate_G1_precomputation affine_ate_G1_precomp_type; + typedef mnt6_affine_ate_G2_precomputation affine_ate_G2_precomp_type; + typedef mnt6_G1_precomp G1_precomp_type; + typedef mnt6_G2_precomp G2_precomp_type; + typedef mnt6_Fq Fq_type; + typedef mnt6_Fq3 Fqe_type; + typedef mnt6_Fq6 Fqk_type; + typedef mnt6_GT GT_type; + + static const bool has_affine_pairing = true; + + static void init_public_params(); + static mnt6_GT final_exponentiation(const mnt6_Fq6 &elt); + static mnt6_G1_precomp precompute_G1(const mnt6_G1 &P); + static mnt6_G2_precomp precompute_G2(const mnt6_G2 &Q); + static mnt6_Fq6 miller_loop(const mnt6_G1_precomp &prec_P, + const mnt6_G2_precomp &prec_Q); + static mnt6_affine_ate_G1_precomputation affine_ate_precompute_G1(const mnt6_G1 &P); + static mnt6_affine_ate_G2_precomputation affine_ate_precompute_G2(const mnt6_G2 &Q); + static mnt6_Fq6 affine_ate_miller_loop(const mnt6_affine_ate_G1_precomputation &prec_P, + const mnt6_affine_ate_G2_precomputation &prec_Q); + static mnt6_Fq6 affine_ate_e_over_e_miller_loop(const mnt6_affine_ate_G1_precomputation &prec_P1, + const mnt6_affine_ate_G2_precomputation &prec_Q1, + const mnt6_affine_ate_G1_precomputation &prec_P2, + const mnt6_affine_ate_G2_precomputation &prec_Q2); + static mnt6_Fq6 affine_ate_e_times_e_over_e_miller_loop(const mnt6_affine_ate_G1_precomputation &prec_P1, + const mnt6_affine_ate_G2_precomputation &prec_Q1, + const mnt6_affine_ate_G1_precomputation &prec_P2, + const mnt6_affine_ate_G2_precomputation &prec_Q2, + const mnt6_affine_ate_G1_precomputation &prec_P3, + const mnt6_affine_ate_G2_precomputation &prec_Q3); + static mnt6_Fq6 double_miller_loop(const mnt6_G1_precomp &prec_P1, + const mnt6_G2_precomp &prec_Q1, + const mnt6_G1_precomp &prec_P2, + const mnt6_G2_precomp &prec_Q2); + + /* the following are used in test files */ + static mnt6_Fq6 pairing(const mnt6_G1 &P, + const mnt6_G2 &Q); + static mnt6_Fq6 reduced_pairing(const mnt6_G1 &P, + const mnt6_G2 &Q); + static mnt6_Fq6 affine_reduced_pairing(const mnt6_G1 &P, + const mnt6_G2 &Q); +}; + +} // libsnark + +#endif // MNT6_PP_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/public_params.hpp b/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/public_params.hpp new file mode 100644 index 0000000..07e0475 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/public_params.hpp @@ -0,0 +1,103 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef PUBLIC_PARAMS_HPP_ +#define PUBLIC_PARAMS_HPP_ +#include + +namespace libsnark { + +/* + for every curve the user should define corresponding + public_params with the following typedefs: + + Fp_type + G1_type + G2_type + G1_precomp_type + G2_precomp_type + affine_ate_G1_precomp_type + affine_ate_G2_precomp_type + Fq_type + Fqe_type + Fqk_type + GT_type + + one should also define the following static methods: + + void init_public_params(); + + GT final_exponentiation(const Fqk &elt); + + G1_precomp precompute_G1(const G1 &P); + G2_precomp precompute_G2(const G2 &Q); + + Fqk miller_loop(const G1_precomp &prec_P, + const G2_precomp &prec_Q); + + affine_ate_G1_precomp affine_ate_precompute_G1(const G1 &P); + affine_ate_G2_precomp affine_ate_precompute_G2(const G2 &Q); + + + Fqk affine_ate_miller_loop(const affine_ate_G1_precomp &prec_P, + const affine_ate_G2_precomp &prec_Q); + Fqk affine_ate_e_over_e_miller_loop(const affine_ate_G1_precomp &prec_P1, + const affine_ate_G2_precomp &prec_Q1, + const affine_ate_G1_precomp &prec_P2, + const affine_ate_G2_precomp &prec_Q2); + Fqk affine_ate_e_times_e_over_e_miller_loop(const affine_ate_G1_precomp &prec_P1, + const affine_ate_G2_precomp &prec_Q1, + const affine_ate_G1_precomp &prec_P2, + const affine_ate_G2_precomp &prec_Q2, + const affine_ate_G1_precomp &prec_P3, + const affine_ate_G2_precomp &prec_Q3); + Fqk double_miller_loop(const G1_precomp &prec_P1, + const G2_precomp &prec_Q1, + const G1_precomp &prec_P2, + const G2_precomp &prec_Q2); + + Fqk pairing(const G1 &P, + const G2 &Q); + GT reduced_pairing(const G1 &P, + const G2 &Q); + GT affine_reduced_pairing(const G1 &P, + const G2 &Q); +*/ + +template +using Fr = typename EC_ppT::Fp_type; +template +using G1 = typename EC_ppT::G1_type; +template +using G2 = typename EC_ppT::G2_type; +template +using G1_precomp = typename EC_ppT::G1_precomp_type; +template +using G2_precomp = typename EC_ppT::G2_precomp_type; +template +using affine_ate_G1_precomp = typename EC_ppT::affine_ate_G1_precomp_type; +template +using affine_ate_G2_precomp = typename EC_ppT::affine_ate_G2_precomp_type; +template +using Fq = typename EC_ppT::Fq_type; +template +using Fqe = typename EC_ppT::Fqe_type; +template +using Fqk = typename EC_ppT::Fqk_type; +template +using GT = typename EC_ppT::GT_type; + +template +using Fr_vector = std::vector >; +template +using G1_vector = std::vector >; +template +using G2_vector = std::vector >; + +} // libsnark + +#endif // PUBLIC_PARAMS_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/tests/test_bilinearity.cpp b/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/tests/test_bilinearity.cpp new file mode 100644 index 0000000..2957452 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/tests/test_bilinearity.cpp @@ -0,0 +1,136 @@ +/** + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ +#include "common/profiling.hpp" +#include "algebra/curves/edwards/edwards_pp.hpp" +#ifdef CURVE_BN128 +#include "algebra/curves/bn128/bn128_pp.hpp" +#endif +#include "algebra/curves/alt_bn128/alt_bn128_pp.hpp" +#include "algebra/curves/mnt/mnt4/mnt4_pp.hpp" +#include "algebra/curves/mnt/mnt6/mnt6_pp.hpp" + +using namespace libsnark; + +template +void pairing_test() +{ + GT GT_one = GT::one(); + + printf("Running bilinearity tests:\n"); + G1 P = (Fr::random_element()) * G1::one(); + //G1 P = Fr("2") * G1::one(); + G2 Q = (Fr::random_element()) * G2::one(); + //G2 Q = Fr("3") * G2::one(); + + printf("P:\n"); + P.print(); + P.print_coordinates(); + printf("Q:\n"); + Q.print(); + Q.print_coordinates(); + printf("\n\n"); + + Fr s = Fr::random_element(); + //Fr s = Fr("2"); + G1 sP = s * P; + G2 sQ = s * Q; + + printf("Pairing bilinearity tests (three must match):\n"); + GT ans1 = ppT::reduced_pairing(sP, Q); + GT ans2 = ppT::reduced_pairing(P, sQ); + GT ans3 = ppT::reduced_pairing(P, Q)^s; + ans1.print(); + ans2.print(); + ans3.print(); + assert(ans1 == ans2); + assert(ans2 == ans3); + + assert(ans1 != GT_one); + assert((ans1^Fr::field_char()) == GT_one); + printf("\n\n"); +} + +template +void double_miller_loop_test() +{ + const G1 P1 = (Fr::random_element()) * G1::one(); + const G1 P2 = (Fr::random_element()) * G1::one(); + const G2 Q1 = (Fr::random_element()) * G2::one(); + const G2 Q2 = (Fr::random_element()) * G2::one(); + + const G1_precomp prec_P1 = ppT::precompute_G1(P1); + const G1_precomp prec_P2 = ppT::precompute_G1(P2); + const G2_precomp prec_Q1 = ppT::precompute_G2(Q1); + const G2_precomp prec_Q2 = ppT::precompute_G2(Q2); + + const Fqk ans_1 = ppT::miller_loop(prec_P1, prec_Q1); + const Fqk ans_2 = ppT::miller_loop(prec_P2, prec_Q2); + const Fqk ans_12 = ppT::double_miller_loop(prec_P1, prec_Q1, prec_P2, prec_Q2); + assert(ans_1 * ans_2 == ans_12); +} + +template +void affine_pairing_test() +{ + GT GT_one = GT::one(); + + printf("Running bilinearity tests:\n"); + G1 P = (Fr::random_element()) * G1::one(); + G2 Q = (Fr::random_element()) * G2::one(); + + printf("P:\n"); + P.print(); + printf("Q:\n"); + Q.print(); + printf("\n\n"); + + Fr s = Fr::random_element(); + G1 sP = s * P; + G2 sQ = s * Q; + + printf("Pairing bilinearity tests (three must match):\n"); + GT ans1 = ppT::affine_reduced_pairing(sP, Q); + GT ans2 = ppT::affine_reduced_pairing(P, sQ); + GT ans3 = ppT::affine_reduced_pairing(P, Q)^s; + ans1.print(); + ans2.print(); + ans3.print(); + assert(ans1 == ans2); + assert(ans2 == ans3); + + assert(ans1 != GT_one); + assert((ans1^Fr::field_char()) == GT_one); + printf("\n\n"); +} + +int main(void) +{ + start_profiling(); + edwards_pp::init_public_params(); + pairing_test(); + double_miller_loop_test(); + + mnt6_pp::init_public_params(); + pairing_test(); + double_miller_loop_test(); + affine_pairing_test(); + + mnt4_pp::init_public_params(); + pairing_test(); + double_miller_loop_test(); + affine_pairing_test(); + + alt_bn128_pp::init_public_params(); + pairing_test(); + double_miller_loop_test(); + +#ifdef CURVE_BN128 // BN128 has fancy dependencies so it may be disabled + bn128_pp::init_public_params(); + pairing_test(); + double_miller_loop_test(); +#endif +} diff --git a/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/tests/test_groups.cpp b/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/tests/test_groups.cpp new file mode 100644 index 0000000..725e490 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/algebra/curves/tests/test_groups.cpp @@ -0,0 +1,175 @@ +/** + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ +#include "common/profiling.hpp" +#include "algebra/curves/edwards/edwards_pp.hpp" +#include "algebra/curves/mnt/mnt4/mnt4_pp.hpp" +#include "algebra/curves/mnt/mnt6/mnt6_pp.hpp" +#ifdef CURVE_BN128 +#include "algebra/curves/bn128/bn128_pp.hpp" +#endif +#include "algebra/curves/alt_bn128/alt_bn128_pp.hpp" +#include + +using namespace libsnark; + +template +void test_mixed_add() +{ + GroupT base, el, result; + + base = GroupT::zero(); + el = GroupT::zero(); + el.to_special(); + result = base.mixed_add(el); + assert(result == base + el); + + base = GroupT::zero(); + el = GroupT::random_element(); + el.to_special(); + result = base.mixed_add(el); + assert(result == base + el); + + base = GroupT::random_element(); + el = GroupT::zero(); + el.to_special(); + result = base.mixed_add(el); + assert(result == base + el); + + base = GroupT::random_element(); + el = GroupT::random_element(); + el.to_special(); + result = base.mixed_add(el); + assert(result == base + el); + + base = GroupT::random_element(); + el = base; + el.to_special(); + result = base.mixed_add(el); + assert(result == base.dbl()); +} + +template +void test_group() +{ + bigint<1> rand1 = bigint<1>("76749407"); + bigint<1> rand2 = bigint<1>("44410867"); + bigint<1> randsum = bigint<1>("121160274"); + + GroupT zero = GroupT::zero(); + assert(zero == zero); + GroupT one = GroupT::one(); + assert(one == one); + GroupT two = bigint<1>(2l) * GroupT::one(); + assert(two == two); + GroupT five = bigint<1>(5l) * GroupT::one(); + + GroupT three = bigint<1>(3l) * GroupT::one(); + GroupT four = bigint<1>(4l) * GroupT::one(); + + assert(two+five == three+four); + + GroupT a = GroupT::random_element(); + GroupT b = GroupT::random_element(); + + assert(one != zero); + assert(a != zero); + assert(a != one); + + assert(b != zero); + assert(b != one); + + assert(a.dbl() == a + a); + assert(b.dbl() == b + b); + assert(one.add(two) == three); + assert(two.add(one) == three); + assert(a + b == b + a); + assert(a - a == zero); + assert(a - b == a + (-b)); + assert(a - b == (-b) + a); + + // handle special cases + assert(zero + (-a) == -a); + assert(zero - a == -a); + assert(a - zero == a); + assert(a + zero == a); + assert(zero + a == a); + + assert((a + b).dbl() == (a + b) + (b + a)); + assert(bigint<1>("2") * (a + b) == (a + b) + (b + a)); + + assert((rand1 * a) + (rand2 * a) == (randsum * a)); + + assert(GroupT::order() * a == zero); + assert(GroupT::order() * one == zero); + assert((GroupT::order() * a) - a != zero); + assert((GroupT::order() * one) - one != zero); + + test_mixed_add(); +} + +template +void test_mul_by_q() +{ + GroupT a = GroupT::random_element(); + assert((GroupT::base_field_char()*a) == a.mul_by_q()); +} + +template +void test_output() +{ + GroupT g = GroupT::zero(); + + for (size_t i = 0; i < 1000; ++i) + { + std::stringstream ss; + ss << g; + GroupT gg; + ss >> gg; + assert(g == gg); + /* use a random point in next iteration */ + g = GroupT::random_element(); + } +} + +int main(void) +{ + edwards_pp::init_public_params(); + test_group >(); + test_output >(); + test_group >(); + test_output >(); + test_mul_by_q >(); + + mnt4_pp::init_public_params(); + test_group >(); + test_output >(); + test_group >(); + test_output >(); + test_mul_by_q >(); + + mnt6_pp::init_public_params(); + test_group >(); + test_output >(); + test_group >(); + test_output >(); + test_mul_by_q >(); + + alt_bn128_pp::init_public_params(); + test_group >(); + test_output >(); + test_group >(); + test_output >(); + test_mul_by_q >(); + +#ifdef CURVE_BN128 // BN128 has fancy dependencies so it may be disabled + bn128_pp::init_public_params(); + test_group >(); + test_output >(); + test_group >(); + test_output >(); +#endif +} diff --git a/privacy/zsl/zsl/snark/libsnark/src/algebra/evaluation_domain/domains/basic_radix2_domain.hpp b/privacy/zsl/zsl/snark/libsnark/src/algebra/evaluation_domain/domains/basic_radix2_domain.hpp new file mode 100644 index 0000000..3e127a0 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/algebra/evaluation_domain/domains/basic_radix2_domain.hpp @@ -0,0 +1,45 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for the "basic radix-2" evaluation domain. + + Roughly, the domain has size m = 2^k and consists of the m-th roots of unity. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef BASIC_RADIX2_DOMAIN_HPP_ +#define BASIC_RADIX2_DOMAIN_HPP_ + +#include "algebra/evaluation_domain/evaluation_domain.hpp" + +namespace libsnark { + +template +class basic_radix2_domain : public evaluation_domain { +public: + + FieldT omega; + + basic_radix2_domain(const size_t m); + + void FFT(std::vector &a); + void iFFT(std::vector &a); + void cosetFFT(std::vector &a, const FieldT &g); + void icosetFFT(std::vector &a, const FieldT &g); + std::vector lagrange_coeffs(const FieldT &t); + FieldT get_element(const size_t idx); + FieldT compute_Z(const FieldT &t); + void add_poly_Z(const FieldT &coeff, std::vector &H); + void divide_by_Z_on_coset(std::vector &P); + +}; + +} // libsnark + +#include "algebra/evaluation_domain/domains/basic_radix2_domain.tcc" + +#endif // BASIC_RADIX2_DOMAIN_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/algebra/evaluation_domain/domains/basic_radix2_domain.tcc b/privacy/zsl/zsl/snark/libsnark/src/algebra/evaluation_domain/domains/basic_radix2_domain.tcc new file mode 100644 index 0000000..d315e83 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/algebra/evaluation_domain/domains/basic_radix2_domain.tcc @@ -0,0 +1,112 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for the "basic radix-2" evaluation domain. + + See basic_radix2_domain.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef BASIC_RADIX2_DOMAIN_TCC_ +#define BASIC_RADIX2_DOMAIN_TCC_ + +#include "algebra/evaluation_domain/domains/basic_radix2_domain_aux.hpp" + +namespace libsnark { + +template +basic_radix2_domain::basic_radix2_domain(const size_t m) : evaluation_domain(m) +{ + assert(m > 1); + const size_t logm = log2(m); + assert(logm <= (FieldT::s)); + + omega = get_root_of_unity(m); +} + +template +void basic_radix2_domain::FFT(std::vector &a) +{ + enter_block("Execute FFT"); + assert(a.size() == this->m); + _basic_radix2_FFT(a, omega); + leave_block("Execute FFT"); +} + +template +void basic_radix2_domain::iFFT(std::vector &a) +{ + enter_block("Execute inverse FFT"); + assert(a.size() == this->m); + _basic_radix2_FFT(a, omega.inverse()); + + const FieldT sconst = FieldT(a.size()).inverse(); + for (size_t i = 0; i < a.size(); ++i) + { + a[i] *= sconst; + } + leave_block("Execute inverse FFT"); +} + +template +void basic_radix2_domain::cosetFFT(std::vector &a, const FieldT &g) +{ + enter_block("Execute coset FFT"); + _multiply_by_coset(a, g); + FFT(a); + leave_block("Execute coset FFT"); +} + +template +void basic_radix2_domain::icosetFFT(std::vector &a, const FieldT &g) +{ + enter_block("Execute inverse coset IFFT"); + iFFT(a); + _multiply_by_coset(a, g.inverse()); + leave_block("Execute inverse coset IFFT"); +} + +template +std::vector basic_radix2_domain::lagrange_coeffs(const FieldT &t) +{ + return _basic_radix2_lagrange_coeffs(this->m, t); +} + +template +FieldT basic_radix2_domain::get_element(const size_t idx) +{ + return omega^idx; +} + +template +FieldT basic_radix2_domain::compute_Z(const FieldT &t) +{ + return (t^this->m) - FieldT::one(); +} + +template +void basic_radix2_domain::add_poly_Z(const FieldT &coeff, std::vector &H) +{ + assert(H.size() == this->m+1); + H[this->m] += coeff; + H[0] -= coeff; +} + +template +void basic_radix2_domain::divide_by_Z_on_coset(std::vector &P) +{ + const FieldT coset = FieldT::multiplicative_generator; + const FieldT Z_inverse_at_coset = this->compute_Z(coset).inverse(); + for (size_t i = 0; i < this->m; ++i) + { + P[i] *= Z_inverse_at_coset; + } +} + +} // libsnark + +#endif // BASIC_RADIX2_DOMAIN_TCC_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/algebra/evaluation_domain/domains/basic_radix2_domain_aux.hpp b/privacy/zsl/zsl/snark/libsnark/src/algebra/evaluation_domain/domains/basic_radix2_domain_aux.hpp new file mode 100644 index 0000000..c42ab2f --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/algebra/evaluation_domain/domains/basic_radix2_domain_aux.hpp @@ -0,0 +1,48 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for auxiliary functions for the "basic radix-2" evaluation domain. + + These functions compute the radix-2 FFT (in single- or multi-thread mode) and, + also compute Lagrange coefficients. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef BASIC_RADIX2_DOMAIN_AUX_HPP_ +#define BASIC_RADIX2_DOMAIN_AUX_HPP_ + +namespace libsnark { + +/** + * Compute the radix-2 FFT of the vector a over the set S={omega^{0},...,omega^{m-1}}. + */ +template +void _basic_radix2_FFT(std::vector &a, const FieldT &omega); + +/** + * A multi-thread version of _basic_radix2_FFT. + */ +template +void _parallel_basic_radix2_FFT(std::vector &a, const FieldT &omega); + +/** + * Translate the vector a to a coset defined by g. + */ +template +void _multiply_by_coset(std::vector &a, const FieldT &g); + +/** + * Compute the m Lagrange coefficients, relative to the set S={omega^{0},...,omega^{m-1}}, at the field element t. + */ +template +std::vector _basic_radix2_lagrange_coeffs(const size_t m, const FieldT &t); + +} // libsnark + +#include "algebra/evaluation_domain/domains/basic_radix2_domain_aux.tcc" + +#endif // BASIC_RADIX2_DOMAIN_AUX_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/algebra/evaluation_domain/domains/basic_radix2_domain_aux.tcc b/privacy/zsl/zsl/snark/libsnark/src/algebra/evaluation_domain/domains/basic_radix2_domain_aux.tcc new file mode 100644 index 0000000..138b82d --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/algebra/evaluation_domain/domains/basic_radix2_domain_aux.tcc @@ -0,0 +1,242 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for auxiliary functions for the "basic radix-2" evaluation domain. + + See basic_radix2_domain_aux.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef BASIC_RADIX2_DOMAIN_AUX_TCC_ +#define BASIC_RADIX2_DOMAIN_AUX_TCC_ + +#include +#ifdef MULTICORE +#include +#endif +#include "algebra/fields/field_utils.hpp" +#include "common/profiling.hpp" +#include "common/utils.hpp" + +namespace libsnark { + +#ifdef MULTICORE +#define _basic_radix2_FFT _basic_parallel_radix2_FFT +#else +#define _basic_radix2_FFT _basic_serial_radix2_FFT +#endif + +/* + Below we make use of pseudocode from [CLRS 2n Ed, pp. 864]. + Also, note that it's the caller's responsibility to multiply by 1/N. + */ +template +void _basic_serial_radix2_FFT(std::vector &a, const FieldT &omega) +{ + const size_t n = a.size(), logn = log2(n); + assert(n == (1u << logn)); + + /* swapping in place (from Storer's book) */ + for (size_t k = 0; k < n; ++k) + { + const size_t rk = bitreverse(k, logn); + if (k < rk) + std::swap(a[k], a[rk]); + } + + size_t m = 1; // invariant: m = 2^{s-1} + for (size_t s = 1; s <= logn; ++s) + { + // w_m is 2^s-th root of unity now + const FieldT w_m = omega^(n/(2*m)); + + asm volatile ("/* pre-inner */"); + for (size_t k = 0; k < n; k += 2*m) + { + FieldT w = FieldT::one(); + for (size_t j = 0; j < m; ++j) + { + const FieldT t = w * a[k+j+m]; + a[k+j+m] = a[k+j] - t; + a[k+j] += t; + w *= w_m; + } + } + asm volatile ("/* post-inner */"); + m *= 2; + } +} + +template +void _basic_parallel_radix2_FFT_inner(std::vector &a, const FieldT &omega, const size_t log_cpus) +{ + const size_t num_cpus = 1ul< > tmp(num_cpus); + for (size_t j = 0; j < num_cpus; ++j) + { + tmp[j].resize(1ul<<(log_m-log_cpus), FieldT::zero()); + } + +#ifdef MULTICORE + #pragma omp parallel for +#endif + for (size_t j = 0; j < num_cpus; ++j) + { + const FieldT omega_j = omega^j; + const FieldT omega_step = omega^(j<<(log_m - log_cpus)); + + FieldT elt = FieldT::one(); + for (size_t i = 0; i < 1ul<<(log_m - log_cpus); ++i) + { + for (size_t s = 0; s < num_cpus; ++s) + { + // invariant: elt is omega^(j*idx) + const size_t idx = (i + (s<<(log_m - log_cpus))) % (1u << log_m); + tmp[j][i] += a[idx] * elt; + elt *= omega_step; + } + elt *= omega_j; + } + } + leave_block("Shuffle inputs"); + + enter_block("Execute sub-FFTs"); + const FieldT omega_num_cpus = omega^num_cpus; + +#ifdef MULTICORE + #pragma omp parallel for +#endif + for (size_t j = 0; j < num_cpus; ++j) + { + _basic_serial_radix2_FFT(tmp[j], omega_num_cpus); + } + leave_block("Execute sub-FFTs"); + + enter_block("Re-shuffle outputs"); + +#ifdef MULTICORE + #pragma omp parallel for +#endif + for (size_t i = 0; i < num_cpus; ++i) + { + for (size_t j = 0; j < 1ul<<(log_m - log_cpus); ++j) + { + // now: i = idx >> (log_m - log_cpus) and j = idx % (1u << (log_m - log_cpus)), for idx = ((i<<(log_m-log_cpus))+j) % (1u << log_m) + a[(j< +void _basic_parallel_radix2_FFT(std::vector &a, const FieldT &omega) +{ +#ifdef MULTICORE + const size_t num_cpus = omp_get_max_threads(); +#else + const size_t num_cpus = 1; +#endif + const size_t log_cpus = ((num_cpus & (num_cpus - 1)) == 0 ? log2(num_cpus) : log2(num_cpus) - 1); + +#ifdef DEBUG + print_indent(); printf("* Invoking parallel FFT on 2^%zu CPUs (omp_get_max_threads = %zu)\n", log_cpus, num_cpus); +#endif + + if (log_cpus == 0) + { + _basic_serial_radix2_FFT(a, omega); + } + else + { + _basic_parallel_radix2_FFT_inner(a, omega, log_cpus); + } +} + +template +void _multiply_by_coset(std::vector &a, const FieldT &g) +{ + //enter_block("Multiply by coset"); + FieldT u = g; + for (size_t i = 1; i < a.size(); ++i) + { + a[i] *= u; + u *= g; + } + //leave_block("Multiply by coset"); +} + +template +std::vector _basic_radix2_lagrange_coeffs(const size_t m, const FieldT &t) +{ + if (m == 1) + { + return std::vector(1, FieldT::one()); + } + + assert(m == (1u << log2(m))); + + const FieldT omega = get_root_of_unity(m); + + std::vector u(m, FieldT::zero()); + + /* + If t equals one of the roots of unity in S={omega^{0},...,omega^{m-1}} + then output 1 at the right place, and 0 elsewhere + */ + + if ((t^m) == (FieldT::one())) + { + FieldT omega_i = FieldT::one(); + for (size_t i = 0; i < m; ++i) + { + if (omega_i == t) // i.e., t equals omega^i + { + u[i] = FieldT::one(); + return u; + } + + omega_i *= omega; + } + } + + /* + Otherwise, if t does not equal any of the roots of unity in S, + then compute each L_{i,S}(t) as Z_{S}(t) * v_i / (t-\omega^i) + where: + - Z_{S}(t) = \prod_{j} (t-\omega^j) = (t^m-1), and + - v_{i} = 1 / \prod_{j \neq i} (\omega^i-\omega^j). + Below we use the fact that v_{0} = 1/m and v_{i+1} = \omega * v_{i}. + */ + + const FieldT Z = (t^m)-FieldT::one(); + FieldT l = Z * FieldT(m).inverse(); + FieldT r = FieldT::one(); + for (size_t i = 0; i < m; ++i) + { + u[i] = l * (t - r).inverse(); + l *= omega; + r *= omega; + } + + return u; +} + +} // libsnark + +#endif // BASIC_RADIX2_DOMAIN_AUX_TCC_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/algebra/evaluation_domain/domains/extended_radix2_domain.hpp b/privacy/zsl/zsl/snark/libsnark/src/algebra/evaluation_domain/domains/extended_radix2_domain.hpp new file mode 100644 index 0000000..59cf898 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/algebra/evaluation_domain/domains/extended_radix2_domain.hpp @@ -0,0 +1,48 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for the "extended radix-2" evaluation domain. + + Roughly, the domain has size m = 2^{k+1} and consists of + "the m-th roots of unity" union "a coset of these roots". + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef EXTENDED_RADIX2_DOMAIN_HPP_ +#define EXTENDED_RADIX2_DOMAIN_HPP_ + +#include "algebra/evaluation_domain/evaluation_domain.hpp" + +namespace libsnark { + +template +class extended_radix2_domain : public evaluation_domain { +public: + + size_t small_m; + FieldT omega; + FieldT shift; + + extended_radix2_domain(const size_t m); + + void FFT(std::vector &a); + void iFFT(std::vector &a); + void cosetFFT(std::vector &a, const FieldT &g); + void icosetFFT(std::vector &a, const FieldT &g); + std::vector lagrange_coeffs(const FieldT &t); + FieldT get_element(const size_t idx); + FieldT compute_Z(const FieldT &t); + void add_poly_Z(const FieldT &coeff, std::vector &H); + void divide_by_Z_on_coset(std::vector &P); + +}; + +} // libsnark + +#include "algebra/evaluation_domain/domains/extended_radix2_domain.tcc" + +#endif // EXTENDED_RADIX2_DOMAIN_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/algebra/evaluation_domain/domains/extended_radix2_domain.tcc b/privacy/zsl/zsl/snark/libsnark/src/algebra/evaluation_domain/domains/extended_radix2_domain.tcc new file mode 100644 index 0000000..bd5c700 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/algebra/evaluation_domain/domains/extended_radix2_domain.tcc @@ -0,0 +1,180 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for the "extended radix-2" evaluation domain. + + See extended_radix2_domain.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef EXTENDED_RADIX2_DOMAIN_TCC_ + +#include "algebra/evaluation_domain/domains/basic_radix2_domain_aux.hpp" + +namespace libsnark { + +template +extended_radix2_domain::extended_radix2_domain(const size_t m) : evaluation_domain(m) +{ + assert(m > 1); + + const size_t logm = log2(m); + + assert(logm == FieldT::s + 1); + + small_m = m/2; + omega = get_root_of_unity(small_m); + shift = coset_shift(); +} + +template +void extended_radix2_domain::FFT(std::vector &a) +{ + assert(a.size() == this->m); + + std::vector a0(small_m, FieldT::zero()); + std::vector a1(small_m, FieldT::zero()); + + const FieldT shift_to_small_m = shift^bigint<1>(small_m); + + FieldT shift_i = FieldT::one(); + for (size_t i = 0; i < small_m; ++i) + { + a0[i] = a[i] + a[small_m + i]; + a1[i] = shift_i * (a[i] + shift_to_small_m * a[small_m + i]); + + shift_i *= shift; + } + + _basic_radix2_FFT(a0, omega); + _basic_radix2_FFT(a1, omega); + + for (size_t i = 0; i < small_m; ++i) + { + a[i] = a0[i]; + a[i+small_m] = a1[i]; + } +} + +template +void extended_radix2_domain::iFFT(std::vector &a) +{ + assert(a.size() == this->m); + + // note: this is not in-place + std::vector a0(a.begin(), a.begin() + small_m); + std::vector a1(a.begin() + small_m, a.end()); + + const FieldT omega_inverse = omega.inverse(); + _basic_radix2_FFT(a0, omega_inverse); + _basic_radix2_FFT(a1, omega_inverse); + + const FieldT shift_to_small_m = shift^bigint<1>(small_m); + const FieldT sconst = (FieldT(small_m) * (FieldT::one()-shift_to_small_m)).inverse(); + + const FieldT shift_inverse = shift.inverse(); + FieldT shift_inverse_i = FieldT::one(); + + for (size_t i = 0; i < small_m; ++i) + { + a[i] = sconst * (-shift_to_small_m * a0[i] + shift_inverse_i * a1[i]); + a[i+small_m] = sconst * (a0[i] - shift_inverse_i * a1[i]); + + shift_inverse_i *= shift_inverse; + } +} + +template +void extended_radix2_domain::cosetFFT(std::vector &a, const FieldT &g) +{ + _multiply_by_coset(a, g); + FFT(a); +} + +template +void extended_radix2_domain::icosetFFT(std::vector &a, const FieldT &g) +{ + iFFT(a); + _multiply_by_coset(a, g.inverse()); +} + +template +std::vector extended_radix2_domain::lagrange_coeffs(const FieldT &t) +{ + const std::vector T0 = _basic_radix2_lagrange_coeffs(small_m, t); + const std::vector T1 = _basic_radix2_lagrange_coeffs(small_m, t * shift.inverse()); + + std::vector result(this->m, FieldT::zero()); + + const FieldT t_to_small_m = t ^ bigint<1>(small_m); + const FieldT shift_to_small_m = shift ^ bigint<1>(small_m); + const FieldT one_over_denom = (shift_to_small_m - FieldT::one()).inverse(); + const FieldT T0_coeff = (t_to_small_m - shift_to_small_m) * (-one_over_denom); + const FieldT T1_coeff = (t_to_small_m - FieldT::one()) * one_over_denom; + for (size_t i = 0; i < small_m; ++i) + { + result[i] = T0[i] * T0_coeff; + result[i+small_m] = T1[i] * T1_coeff; + } + + return result; +} + +template +FieldT extended_radix2_domain::get_element(const size_t idx) +{ + if (idx < small_m) + { + return omega^idx; + } + else + { + return shift*(omega^(idx-small_m)); + } +} + +template +FieldT extended_radix2_domain::compute_Z(const FieldT &t) +{ + return ((t^small_m) - FieldT::one()) * ((t^small_m) - (shift^small_m)); +} + +template +void extended_radix2_domain::add_poly_Z(const FieldT &coeff, std::vector &H) +{ + assert(H.size() == this->m+1); + const FieldT shift_to_small_m = shift^small_m; + + H[this->m] += coeff; + H[small_m] -= coeff * (shift_to_small_m + FieldT::one()); + H[0] += coeff * shift_to_small_m; +} + +template +void extended_radix2_domain::divide_by_Z_on_coset(std::vector &P) +{ + const FieldT coset = FieldT::multiplicative_generator; + + const FieldT coset_to_small_m = coset^small_m; + const FieldT shift_to_small_m = shift^small_m; + + const FieldT Z0 = (coset_to_small_m - FieldT::one()) * (coset_to_small_m - shift_to_small_m); + const FieldT Z1 = (coset_to_small_m*shift_to_small_m - FieldT::one()) * (coset_to_small_m * shift_to_small_m - shift_to_small_m); + + const FieldT Z0_inverse = Z0.inverse(); + const FieldT Z1_inverse = Z1.inverse(); + + for (size_t i = 0; i < small_m; ++i) + { + P[i] *= Z0_inverse; + P[i+small_m] *= Z1_inverse; + } +} + +} // libsnark + +#endif // EXTENDED_RADIX2_DOMAIN_TCC_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/algebra/evaluation_domain/domains/step_radix2_domain.hpp b/privacy/zsl/zsl/snark/libsnark/src/algebra/evaluation_domain/domains/step_radix2_domain.hpp new file mode 100644 index 0000000..ae9818a --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/algebra/evaluation_domain/domains/step_radix2_domain.hpp @@ -0,0 +1,50 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for the "step radix-2" evaluation domain. + + Roughly, the domain has size m = 2^k + 2^r and consists of + "the 2^k-th roots of unity" union "a coset of 2^r-th roots of unity". + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef STEP_RADIX2_DOMAIN_HPP_ +#define STEP_RADIX2_DOMAIN_HPP_ + +#include "algebra/evaluation_domain/evaluation_domain.hpp" + +namespace libsnark { + +template +class step_radix2_domain : public evaluation_domain { +public: + + size_t big_m; + size_t small_m; + FieldT omega; + FieldT big_omega; + FieldT small_omega; + + step_radix2_domain(const size_t m); + + void FFT(std::vector &a); + void iFFT(std::vector &a); + void cosetFFT(std::vector &a, const FieldT &g); + void icosetFFT(std::vector &a, const FieldT &g); + std::vector lagrange_coeffs(const FieldT &t); + FieldT get_element(const size_t idx); + FieldT compute_Z(const FieldT &t); + void add_poly_Z(const FieldT &coeff, std::vector &H); + void divide_by_Z_on_coset(std::vector &P); + +}; + +} // libsnark + +#include "algebra/evaluation_domain/domains/step_radix2_domain.tcc" + +#endif // STEP_RADIX2_DOMAIN_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/algebra/evaluation_domain/domains/step_radix2_domain.tcc b/privacy/zsl/zsl/snark/libsnark/src/algebra/evaluation_domain/domains/step_radix2_domain.tcc new file mode 100644 index 0000000..af9fa29 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/algebra/evaluation_domain/domains/step_radix2_domain.tcc @@ -0,0 +1,247 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for the "step radix-2" evaluation domain. + + See step_radix2_domain.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef STEP_RADIX2_DOMAIN_TCC_ + +#include "algebra/evaluation_domain/domains/basic_radix2_domain_aux.hpp" + +namespace libsnark { + +template +step_radix2_domain::step_radix2_domain(const size_t m) : evaluation_domain(m) +{ + assert(m > 1); + + big_m = 1ul<<(log2(m)-1); + small_m = m - big_m; + + assert(small_m == 1ul<(1ul<(small_m); +} + +template +void step_radix2_domain::FFT(std::vector &a) +{ + assert(a.size() == this->m); + std::vector c(big_m, FieldT::zero()); + std::vector d(big_m, FieldT::zero()); + + FieldT omega_i = FieldT::one(); + for (size_t i = 0; i < big_m; ++i) + { + c[i] = (i < small_m ? a[i] + a[i+big_m] : a[i]); + d[i] = omega_i * (i < small_m ? a[i] - a[i+big_m] : a[i]); + omega_i *= omega; + } + + std::vector e(small_m, FieldT::zero()); + const size_t compr = 1ul<<(log2(big_m) - log2(small_m)); + for (size_t i = 0; i < small_m; ++i) + { + for (size_t j = 0; j < compr; ++j) + { + e[i] += d[i + j * small_m]; + } + } + + _basic_radix2_FFT(c, omega.squared()); + _basic_radix2_FFT(e, get_root_of_unity(small_m)); + + for (size_t i = 0; i < big_m; ++i) + { + a[i] = c[i]; + } + + for (size_t i = 0; i < small_m; ++i) + { + a[i+big_m] = e[i]; + } +} + +template +void step_radix2_domain::iFFT(std::vector &a) +{ + assert(a.size() == this->m); + + std::vector U0(a.begin(), a.begin() + big_m); + std::vector U1(a.begin() + big_m, a.end()); + + _basic_radix2_FFT(U0, omega.squared().inverse()); + _basic_radix2_FFT(U1, get_root_of_unity(small_m).inverse()); + + const FieldT U0_size_inv = FieldT(big_m).inverse(); + for (size_t i = 0; i < big_m; ++i) + { + U0[i] *= U0_size_inv; + } + + const FieldT U1_size_inv = FieldT(small_m).inverse(); + for (size_t i = 0; i < small_m; ++i) + { + U1[i] *= U1_size_inv; + } + + std::vector tmp = U0; + FieldT omega_i = FieldT::one(); + for (size_t i = 0; i < big_m; ++i) + { + tmp[i] *= omega_i; + omega_i *= omega; + } + + // save A_suffix + for (size_t i = small_m; i < big_m; ++i) + { + a[i] = U0[i]; + } + + const size_t compr = 1ul<<(log2(big_m) - log2(small_m)); + for (size_t i = 0; i < small_m; ++i) + { + for (size_t j = 1; j < compr; ++j) + { + U1[i] -= tmp[i + j * small_m]; + } + } + + const FieldT omega_inv = omega.inverse(); + FieldT omega_inv_i = FieldT::one(); + for (size_t i = 0; i < small_m; ++i) + { + U1[i] *= omega_inv_i; + omega_inv_i *= omega_inv; + } + + // compute A_prefix + const FieldT over_two = FieldT(2).inverse(); + for (size_t i = 0; i < small_m; ++i) + { + a[i] = (U0[i]+U1[i]) * over_two; + } + + // compute B2 + for (size_t i = 0; i < small_m; ++i) + { + a[big_m + i] = (U0[i]-U1[i]) * over_two; + } +} + +template +void step_radix2_domain::cosetFFT(std::vector &a, const FieldT &g) +{ + _multiply_by_coset(a, g); + FFT(a); +} + +template +void step_radix2_domain::icosetFFT(std::vector &a, const FieldT &g) +{ + iFFT(a); + _multiply_by_coset(a, g.inverse()); +} + +template +std::vector step_radix2_domain::lagrange_coeffs(const FieldT &t) +{ + std::vector inner_big = _basic_radix2_lagrange_coeffs(big_m, t); + std::vector inner_small = _basic_radix2_lagrange_coeffs(small_m, t * omega.inverse()); + + std::vector result(this->m, FieldT::zero()); + + const FieldT L0 = (t^small_m)-(omega^small_m); + const FieldT omega_to_small_m = omega^small_m; + const FieldT big_omega_to_small_m = big_omega ^ small_m; + FieldT elt = FieldT::one(); + for (size_t i = 0; i < big_m; ++i) + { + result[i] = inner_big[i] * L0 * (elt - omega_to_small_m).inverse(); + elt *= big_omega_to_small_m; + } + + const FieldT L1 = ((t^big_m)-FieldT::one()) * ((omega^big_m) - FieldT::one()).inverse(); + + for (size_t i = 0; i < small_m; ++i) + { + result[big_m + i] = L1 * inner_small[i]; + } + + return result; +} + +template +FieldT step_radix2_domain::get_element(const size_t idx) +{ + if (idx < big_m) + { + return big_omega^idx; + } + else + { + return omega * (small_omega^(idx-big_m)); + } +} + +template +FieldT step_radix2_domain::compute_Z(const FieldT &t) +{ + return ((t^big_m) - FieldT::one()) * ((t^small_m) - (omega^small_m)); +} + +template +void step_radix2_domain::add_poly_Z(const FieldT &coeff, std::vector &H) +{ + assert(H.size() == this->m+1); + const FieldT omega_to_small_m = omega^small_m; + + H[this->m] += coeff; + H[big_m] -= coeff * omega_to_small_m; + H[small_m] -= coeff; + H[0] += coeff * omega_to_small_m; +} + +template +void step_radix2_domain::divide_by_Z_on_coset(std::vector &P) +{ + // (c^{2^k}-1) * (c^{2^r} * w^{2^{r+1}*i) - w^{2^r}) + const FieldT coset = FieldT::multiplicative_generator; + + const FieldT Z0 = (coset^big_m) - FieldT::one(); + const FieldT coset_to_small_m_times_Z0 = (coset^small_m) * Z0; + const FieldT omega_to_small_m_times_Z0 = (omega^small_m) * Z0; + const FieldT omega_to_2small_m = omega^(2*small_m); + FieldT elt = FieldT::one(); + + for (size_t i = 0; i < big_m; ++i) + { + P[i] *= (coset_to_small_m_times_Z0 * elt - omega_to_small_m_times_Z0).inverse(); + elt *= omega_to_2small_m; + } + + // (c^{2^k}*w^{2^k}-1) * (c^{2^k} * w^{2^r} - w^{2^r}) + + const FieldT Z1 = ((((coset*omega)^big_m) - FieldT::one()) * (((coset * omega)^small_m) - (omega^small_m))); + const FieldT Z1_inverse = Z1.inverse(); + + for (size_t i = 0; i < small_m; ++i) + { + P[big_m + i] *= Z1_inverse; + } + +} + +} // libsnark + +#endif // STEP_RADIX2_DOMAIN_TCC_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/algebra/evaluation_domain/evaluation_domain.hpp b/privacy/zsl/zsl/snark/libsnark/src/algebra/evaluation_domain/evaluation_domain.hpp new file mode 100644 index 0000000..358db97 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/algebra/evaluation_domain/evaluation_domain.hpp @@ -0,0 +1,125 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for evaluation domains. + + Roughly, given a desired size m for the domain, the constructor selects + a choice of domain S with size ~m that has been selected so to optimize + - computations of Lagrange polynomials, and + - FFT/iFFT computations. + An evaluation domain also provides other other functions, e.g., accessing + individual elements in S or evaluating its vanishing polynomial. + + The descriptions below make use of the definition of a *Lagrange polynomial*, + which we recall. Given a field F, a subset S=(a_i)_i of F, and an index idx + in {0,...,|S-1|}, the idx-th Lagrange polynomial (wrt to subset S) is defined to be + \f[ L_{idx,S}(z) := prod_{k \neq idx} (z - a_k) / prod_{k \neq idx} (a_{idx} - a_k) \f] + Note that, by construction: + \f[ \forall j \neq idx: L_{idx,S}(a_{idx}) = 1 \text{ and } L_{idx,S}(a_j) = 0 \f] + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef EVALUATION_DOMAIN_HPP_ +#define EVALUATION_DOMAIN_HPP_ + +#include + +namespace libsnark { + +/** + * An evaluation domain. + */ +template +class evaluation_domain { +public: + + const size_t m; + + /** + * Construct an evaluation domain S of size m, if possible. + * + * (See the function get_evaluation_domain below.) + */ + evaluation_domain(const size_t m) : m(m) {}; + + /** + * Get the idx-th element in S. + */ + virtual FieldT get_element(const size_t idx) = 0; + + /** + * Compute the FFT, over the domain S, of the vector a. + */ + virtual void FFT(std::vector &a) = 0; + + /** + * Compute the inverse FFT, over the domain S, of the vector a. + */ + virtual void iFFT(std::vector &a) = 0; + + /** + * Compute the FFT, over the domain g*S, of the vector a. + */ + virtual void cosetFFT(std::vector &a, const FieldT &g) = 0; + + /** + * Compute the inverse FFT, over the domain g*S, of the vector a. + */ + virtual void icosetFFT(std::vector &a, const FieldT &g) = 0; + + /** + * Evaluate all Lagrange polynomials. + * + * The inputs are: + * - an integer m + * - an element t + * The output is a vector (b_{0},...,b_{m-1}) + * where b_{i} is the evaluation of L_{i,S}(z) at z = t. + */ + virtual std::vector lagrange_coeffs(const FieldT &t) = 0; + + /** + * Evaluate the vanishing polynomial of S at the field element t. + */ + virtual FieldT compute_Z(const FieldT &t) = 0; + + /** + * Add the coefficients of the vanishing polynomial of S to the coefficients of the polynomial H. + */ + virtual void add_poly_Z(const FieldT &coeff, std::vector &H) = 0; + + /** + * Multiply by the evaluation, on a coset of S, of the inverse of the vanishing polynomial of S. + */ + virtual void divide_by_Z_on_coset(std::vector &P) = 0; +}; + +/** + * Return an evaluation domain object in which the domain S has size |S| >= min_size. + * The function chooses from different supported domains, depending on min_size. + */ +template +std::shared_ptr > get_evaluation_domain(const size_t min_size); + +/** + * Naive evaluation of a *single* Lagrange polynomial, used for testing purposes. + * + * The inputs are: + * - an integer m + * - a domain S = (a_{0},...,a_{m-1}) of size m + * - a field element element t + * - an index idx in {0,...,m-1} + * The output is the polynomial L_{idx,S}(z) evaluated at z = t. + */ +template +FieldT lagrange_eval(const size_t m, const std::vector &domain, const FieldT &t, const size_t idx); + +} // libsnark + +#include "algebra/evaluation_domain/evaluation_domain.tcc" + +#endif // EVALUATION_DOMAIN_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/algebra/evaluation_domain/evaluation_domain.tcc b/privacy/zsl/zsl/snark/libsnark/src/algebra/evaluation_domain/evaluation_domain.tcc new file mode 100644 index 0000000..47d0495 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/algebra/evaluation_domain/evaluation_domain.tcc @@ -0,0 +1,119 @@ +/** @file + ***************************************************************************** + + Imeplementation of interfaces for evaluation domains. + + See evaluation_domain.hpp . + + We currently implement, and select among, three types of domains: + - "basic radix-2": the domain has size m = 2^k and consists of the m-th roots of unity + - "extended radix-2": the domain has size m = 2^{k+1} and consists of "the m-th roots of unity" union "a coset" + - "step radix-2": the domain has size m = 2^k + 2^r and consists of "the 2^k-th roots of unity" union "a coset of 2^r-th roots of unity" + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef EVALUATION_DOMAIN_TCC_ +#define EVALUATION_DOMAIN_TCC_ + +#include +#include "algebra/fields/field_utils.hpp" +#include "algebra/evaluation_domain/domains/basic_radix2_domain.hpp" +#include "algebra/evaluation_domain/domains/extended_radix2_domain.hpp" +#include "algebra/evaluation_domain/domains/step_radix2_domain.hpp" + +namespace libsnark { + +template +std::shared_ptr > get_evaluation_domain(const size_t min_size) +{ + assert(min_size > 1); + const size_t log_min_size = log2(min_size); + assert(log_min_size <= (FieldT::s+1)); + + std::shared_ptr > result; + if (min_size == (1u << log_min_size)) + { + if (log_min_size == FieldT::s+1) + { + if (!inhibit_profiling_info) + { + print_indent(); printf("* Selected domain: extended_radix2\n"); + } + result.reset(new extended_radix2_domain(min_size)); + } + else + { + if (!inhibit_profiling_info) + { + print_indent(); printf("* Selected domain: basic_radix2\n"); + } + result.reset(new basic_radix2_domain(min_size)); + } + } + else + { + const size_t big = 1ul<<(log2(min_size)-1); + const size_t small = min_size - big; + const size_t rounded_small = (1ul<(big + rounded_small)); + } + else + { + if (!inhibit_profiling_info) + { + print_indent(); printf("* Selected domain: extended_radix2\n"); + } + result.reset(new extended_radix2_domain(big + rounded_small)); + } + } + else + { + if (!inhibit_profiling_info) + { + print_indent(); printf("* Selected domain: step_radix2\n"); + } + result.reset(new step_radix2_domain(big + rounded_small)); + } + } + + return result; +} + +template +FieldT lagrange_eval(const size_t m, const std::vector &domain, const FieldT &t, const size_t idx) +{ + assert(m == domain.size()); + assert(idx < m); + + FieldT num = FieldT::one(); + FieldT denom = FieldT::one(); + + for (size_t k = 0; k < m; ++k) + { + if (k == idx) + { + continue; + } + + num *= t - domain[k]; + denom *= domain[idx] - domain[k]; + } + + return num * denom.inverse(); +} + +} // libsnark + +#endif // EVALUATION_DOMAIN_TCC_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/algebra/exponentiation/exponentiation.hpp b/privacy/zsl/zsl/snark/libsnark/src/algebra/exponentiation/exponentiation.hpp new file mode 100644 index 0000000..a8a2c92 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/algebra/exponentiation/exponentiation.hpp @@ -0,0 +1,31 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for (square-and-multiply) exponentiation. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef EXPONENTIATION_HPP_ +#define EXPONENTIATION_HPP_ + +#include + +#include "algebra/fields/bigint.hpp" + +namespace libsnark { + +template +FieldT power(const FieldT &base, const bigint &exponent); + +template +FieldT power(const FieldT &base, const unsigned long exponent); + +} // libsnark + +#include "algebra/exponentiation/exponentiation.tcc" + +#endif // EXPONENTIATION_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/algebra/exponentiation/exponentiation.tcc b/privacy/zsl/zsl/snark/libsnark/src/algebra/exponentiation/exponentiation.tcc new file mode 100644 index 0000000..dd557eb --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/algebra/exponentiation/exponentiation.tcc @@ -0,0 +1,53 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for (square-and-multiply) exponentiation. + + See exponentiation.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef EXPONENTIATION_TCC_ +#define EXPONENTIATION_TCC_ + +#include "common/utils.hpp" + +namespace libsnark { + +template +FieldT power(const FieldT &base, const bigint &exponent) +{ + FieldT result = FieldT::one(); + + bool found_one = false; + + for (long i = exponent.max_bits() - 1; i >= 0; --i) + { + if (found_one) + { + result = result * result; + } + + if (exponent.test_bit(i)) + { + found_one = true; + result = result * base; + } + } + + return result; +} + +template +FieldT power(const FieldT &base, const unsigned long exponent) +{ + return power(base, bigint<1>(exponent)); +} + +} // libsnark + +#endif // EXPONENTIATION_TCC_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/algebra/fields/bigint.hpp b/privacy/zsl/zsl/snark/libsnark/src/algebra/fields/bigint.hpp new file mode 100644 index 0000000..7331e9d --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/algebra/fields/bigint.hpp @@ -0,0 +1,61 @@ +/** @file + ***************************************************************************** + Declaration of bigint wrapper class around GMP's MPZ long integers. + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef BIGINT_HPP_ +#define BIGINT_HPP_ +#include +#include +#include +#include "common/serialization.hpp" + +namespace libsnark { + +template class bigint; +template std::ostream& operator<<(std::ostream &, const bigint&); +template std::istream& operator>>(std::istream &, bigint&); + +/** + * Wrapper class around GMP's MPZ long integers. It supports arithmetic operations, + * serialization and randomization. Serialization is fragile, see common/serialization.hpp. + */ + +template +class bigint { +public: + static const mp_size_t N = n; + + mp_limb_t data[n] = {0}; + + bigint() = default; + bigint(const unsigned long x); /// Initalize from a small integer + bigint(const char* s); /// Initialize from a string containing an integer in decimal notation + bigint(const mpz_t r); /// Initialize from MPZ element + + void print() const; + void print_hex() const; + bool operator==(const bigint& other) const; + bool operator!=(const bigint& other) const; + void clear(); + bool is_zero() const; + size_t max_bits() const { return n * GMP_NUMB_BITS; } /// Returns the number of bits representable by this bigint type + size_t num_bits() const; /// Returns the number of bits in this specific bigint value, i.e., position of the most-significant 1 in binary + + unsigned long as_ulong() const; /// Return the last limb of the integer + void to_mpz(mpz_t r) const; + bool test_bit(const std::size_t bitno) const; + + bigint& randomize(); + + friend std::ostream& operator<< (std::ostream &out, const bigint &b); + friend std::istream& operator>> (std::istream &in, bigint &b); +}; + +} // libsnark +#include "algebra/fields/bigint.tcc" +#endif diff --git a/privacy/zsl/zsl/snark/libsnark/src/algebra/fields/bigint.tcc b/privacy/zsl/zsl/snark/libsnark/src/algebra/fields/bigint.tcc new file mode 100644 index 0000000..9db5d32 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/algebra/fields/bigint.tcc @@ -0,0 +1,222 @@ +/** @file + ***************************************************************************** + Implementation of bigint wrapper class around GMP's MPZ long integers. + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef BIGINT_TCC_ +#define BIGINT_TCC_ +#include +#include + +namespace libsnark { + +template +bigint::bigint(const unsigned long x) /// Initalize from a small integer +{ + assert(8*sizeof(x) <= GMP_NUMB_BITS); + this->data[0] = x; +} + +template +bigint::bigint(const char* s) /// Initialize from a string containing an integer in decimal notation +{ + size_t l = strlen(s); + unsigned char* s_copy = new unsigned char[l]; + + for (size_t i = 0; i < l; ++i) + { + assert(s[i] >= '0' && s[i] <= '9'); + s_copy[i] = s[i] - '0'; + } + + mp_size_t limbs_written = mpn_set_str(this->data, s_copy, l, 10); + assert(limbs_written <= n); + + delete[] s_copy; +} + +template +bigint::bigint(const mpz_t r) /// Initialize from MPZ element +{ + mpz_t k; + mpz_init_set(k, r); + + for (size_t i = 0; i < n; ++i) + { + data[i] = mpz_get_ui(k); + mpz_fdiv_q_2exp(k, k, GMP_NUMB_BITS); + } + + assert(mpz_sgn(k) == 0); + mpz_clear(k); +} + +template +void bigint::print() const +{ + gmp_printf("%Nd\n", this->data, n); +} + +template +void bigint::print_hex() const +{ + gmp_printf("%Nx\n", this->data, n); +} + +template +bool bigint::operator==(const bigint& other) const +{ + return (mpn_cmp(this->data, other.data, n) == 0); +} + +template +bool bigint::operator!=(const bigint& other) const +{ + return !(operator==(other)); +} + +template +void bigint::clear() +{ + mpn_zero(this->data, n); +} + +template +bool bigint::is_zero() const +{ + for (size_t i = 0; i < n; ++i) + { + if (this->data[i]) + { + return false; + } + } + + return true; +} + +template +size_t bigint::num_bits() const +{ +/* + for (long i = max_bits(); i >= 0; --i) + { + if (this->test_bit(i)) + { + return i+1; + } + } + + return 0; +*/ + for (long i = n-1; i >= 0; --i) + { + mp_limb_t x = this->data[i]; + if (x == 0) + { + continue; + } + else + { + return ((i+1) * GMP_NUMB_BITS) - __builtin_clzl(x); + } + } + return 0; +} + +template +unsigned long bigint::as_ulong() const +{ + return this->data[0]; +} + +template +void bigint::to_mpz(mpz_t r) const +{ + mpz_set_ui(r, 0); + + for (int i = n-1; i >= 0; --i) + { + mpz_mul_2exp(r, r, GMP_NUMB_BITS); + mpz_add_ui(r, r, this->data[i]); + } +} + +template +bool bigint::test_bit(const std::size_t bitno) const +{ + if (bitno >= n * GMP_NUMB_BITS) + { + return false; + } + else + { + const std::size_t part = bitno/GMP_NUMB_BITS; + const std::size_t bit = bitno - (GMP_NUMB_BITS*part); + const mp_limb_t one = 1; + return (this->data[part] & (one< +bigint& bigint::randomize() +{ + assert(GMP_NUMB_BITS == sizeof(mp_limb_t) * 8); + FILE *fp = fopen("/dev/urandom", "r"); //TODO Remove hard-coded use of /dev/urandom. + size_t bytes_read = fread(this->data, 1, sizeof(mp_limb_t) * n, fp); + assert(bytes_read == sizeof(mp_limb_t) * n); + fclose(fp); + + return (*this); +} + + +template +std::ostream& operator<<(std::ostream &out, const bigint &b) +{ +#ifdef BINARY_OUTPUT + out.write((char*)b.data, sizeof(b.data[0]) * n); +#else + mpz_t t; + mpz_init(t); + b.to_mpz(t); + + out << t; + + mpz_clear(t); +#endif + return out; +} + +template +std::istream& operator>>(std::istream &in, bigint &b) +{ +#ifdef BINARY_OUTPUT + in.read((char*)b.data, sizeof(b.data[0]) * n); +#else + std::string s; + in >> s; + + size_t l = s.size(); + unsigned char* s_copy = new unsigned char[l]; + + for (size_t i = 0; i < l; ++i) + { + assert(s[i] >= '0' && s[i] <= '9'); + s_copy[i] = s[i] - '0'; + } + + mp_size_t limbs_written = mpn_set_str(b.data, s_copy, l, 10); + assert(limbs_written <= n); + + delete[] s_copy; +#endif + return in; +} + +} // libsnark +#endif // BIGINT_TCC_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/algebra/fields/field_utils.hpp b/privacy/zsl/zsl/snark/libsnark/src/algebra/fields/field_utils.hpp new file mode 100644 index 0000000..a07ecfe --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/algebra/fields/field_utils.hpp @@ -0,0 +1,51 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef FIELD_UTILS_HPP_ +#define FIELD_UTILS_HPP_ +#include + +#include "common/utils.hpp" +#include "algebra/fields/bigint.hpp" + +namespace libsnark { + +// returns root of unity of order n (for n a power of 2), if one exists +template +FieldT get_root_of_unity(const size_t n); + +template +std::vector pack_int_vector_into_field_element_vector(const std::vector &v, const size_t w); + +template +std::vector pack_bit_vector_into_field_element_vector(const bit_vector &v, const size_t chunk_bits); + +template +std::vector pack_bit_vector_into_field_element_vector(const bit_vector &v); + +template +std::vector convert_bit_vector_to_field_element_vector(const bit_vector &v); + +template +bit_vector convert_field_element_vector_to_bit_vector(const std::vector &v); + +template +bit_vector convert_field_element_to_bit_vector(const FieldT &el); + +template +bit_vector convert_field_element_to_bit_vector(const FieldT &el, const size_t bitcount); + +template +FieldT convert_bit_vector_to_field_element(const bit_vector &v); + +template +void batch_invert(std::vector &vec); + +} // libsnark +#include "algebra/fields/field_utils.tcc" + +#endif // FIELD_UTILS_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/algebra/fields/field_utils.tcc b/privacy/zsl/zsl/snark/libsnark/src/algebra/fields/field_utils.tcc new file mode 100644 index 0000000..13197b2 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/algebra/fields/field_utils.tcc @@ -0,0 +1,183 @@ +/** @file + ***************************************************************************** + Implementation of misc. math and serialization utility functions + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef FIELD_UTILS_TCC_ +#define FIELD_UTILS_TCC_ + +#include "common/utils.hpp" + +namespace libsnark { + +template +FieldT coset_shift() +{ + return FieldT::multiplicative_generator.squared(); +} + +template +FieldT get_root_of_unity(const size_t n) +{ + const size_t logn = log2(n); + assert(n == (1u << logn)); + assert(logn <= FieldT::s); + + FieldT omega = FieldT::root_of_unity; + for (size_t i = FieldT::s; i > logn; --i) + { + omega *= omega; + } + + return omega; +} + +template +std::vector pack_int_vector_into_field_element_vector(const std::vector &v, const size_t w) +{ + const size_t chunk_bits = FieldT::capacity(); + const size_t repacked_size = div_ceil(v.size() * w, chunk_bits); + std::vector result(repacked_size); + + for (size_t i = 0; i < repacked_size; ++i) + { + bigint b; + for (size_t j = 0; j < chunk_bits; ++j) + { + const size_t word_index = (i * chunk_bits + j) / w; + const size_t pos_in_word = (i * chunk_bits + j) % w; + const size_t word_or_0 = (word_index < v.size() ? v[word_index] : 0); + const size_t bit = (word_or_0 >> pos_in_word) & 1; + + b.data[j / GMP_NUMB_BITS] |= bit << (j % GMP_NUMB_BITS); + } + result[i] = FieldT(b); + } + + return result; +} + +template +std::vector pack_bit_vector_into_field_element_vector(const bit_vector &v, const size_t chunk_bits) +{ + assert(chunk_bits <= FieldT::capacity()); + + const size_t repacked_size = div_ceil(v.size(), chunk_bits); + std::vector result(repacked_size); + + for (size_t i = 0; i < repacked_size; ++i) + { + bigint b; + for (size_t j = 0; j < chunk_bits; ++j) + { + b.data[j / GMP_NUMB_BITS] |= ((i * chunk_bits + j) < v.size() && v[i * chunk_bits + j] ? 1ll : 0ll) << (j % GMP_NUMB_BITS); + } + result[i] = FieldT(b); + } + + return result; +} + +template +std::vector pack_bit_vector_into_field_element_vector(const bit_vector &v) +{ + return pack_bit_vector_into_field_element_vector(v, FieldT::capacity()); +} + +template +std::vector convert_bit_vector_to_field_element_vector(const bit_vector &v) +{ + std::vector result; + result.reserve(v.size()); + + for (const bool b : v) + { + result.emplace_back(b ? FieldT::one() : FieldT::zero()); + } + + return result; +} + +template +bit_vector convert_field_element_vector_to_bit_vector(const std::vector &v) +{ + bit_vector result; + + for (const FieldT &el : v) + { + const bit_vector el_bits = convert_field_element_to_bit_vector(el); + result.insert(result.end(), el_bits.begin(), el_bits.end()); + } + + return result; +} + +template +bit_vector convert_field_element_to_bit_vector(const FieldT &el) +{ + bit_vector result; + + bigint b = el.as_bigint(); + for (size_t i = 0; i < FieldT::size_in_bits(); ++i) + { + result.push_back(b.test_bit(i)); + } + + return result; +} + +template +bit_vector convert_field_element_to_bit_vector(const FieldT &el, const size_t bitcount) +{ + bit_vector result = convert_field_element_to_bit_vector(el); + result.resize(bitcount); + + return result; +} + +template +FieldT convert_bit_vector_to_field_element(const bit_vector &v) +{ + assert(v.size() <= FieldT::size_in_bits()); + + FieldT res = FieldT::zero(); + FieldT c = FieldT::one(); + for (bool b : v) + { + res += b ? c : FieldT::zero(); + c += c; + } + return res; +} + +template +void batch_invert(std::vector &vec) +{ + std::vector prod; + prod.reserve(vec.size()); + + FieldT acc = FieldT::one(); + + for (auto el : vec) + { + assert(!el.is_zero()); + prod.emplace_back(acc); + acc = acc * el; + } + + FieldT acc_inverse = acc.inverse(); + + for (long i = vec.size()-1; i >= 0; --i) + { + const FieldT old_el = vec[i]; + vec[i] = acc_inverse * prod[i]; + acc_inverse = acc_inverse * old_el; + } +} + +} // libsnark +#endif // FIELD_UTILS_TCC_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/algebra/fields/fp.hpp b/privacy/zsl/zsl/snark/libsnark/src/algebra/fields/fp.hpp new file mode 100644 index 0000000..a498683 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/algebra/fields/fp.hpp @@ -0,0 +1,182 @@ +/** @file + ***************************************************************************** + Declaration of arithmetic in the finite field F[p], for prime p of fixed length. + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef FP_HPP_ +#define FP_HPP_ + +#include "algebra/fields/bigint.hpp" +#include "algebra/exponentiation/exponentiation.hpp" + +namespace libsnark { + +template& modulus> +class Fp_model; + +template& modulus> +std::ostream& operator<<(std::ostream &, const Fp_model&); + +template& modulus> +std::istream& operator>>(std::istream &, Fp_model &); + +/** + * Arithmetic in the finite field F[p], for prime p of fixed length. + * + * This class implements Fp-arithmetic, for a large prime p, using a fixed number + * of words. It is optimized for tight memory consumption, so the modulus p is + * passed as a template parameter, to avoid per-element overheads. + * + * The implementation is mostly a wrapper around GMP's MPN (constant-size integers). + * But for the integer sizes of interest for libsnark (3 to 5 limbs of 64 bits each), + * we implement performance-critical routines, like addition and multiplication, + * using hand-optimzied assembly code. +*/ +template& modulus> +class Fp_model { +public: + bigint mont_repr; +public: + static const mp_size_t num_limbs = n; + static const constexpr bigint& mod = modulus; +#ifdef PROFILE_OP_COUNTS + static long long add_cnt; + static long long sub_cnt; + static long long mul_cnt; + static long long sqr_cnt; + static long long inv_cnt; +#endif + static size_t num_bits; + static bigint euler; // (modulus-1)/2 + static size_t s; // modulus = 2^s * t + 1 + static bigint t; // with t odd + static bigint t_minus_1_over_2; // (t-1)/2 + static Fp_model nqr; // a quadratic nonresidue + static Fp_model nqr_to_t; // nqr^t + static Fp_model multiplicative_generator; // generator of Fp^* + static Fp_model root_of_unity; // generator^((modulus-1)/2^s) + static mp_limb_t inv; // modulus^(-1) mod W, where W = 2^(word size) + static bigint Rsquared; // R^2, where R = W^k, where k = ?? + static bigint Rcubed; // R^3 + + static bool modulus_is_valid() { return modulus.data[n-1] != 0; } // mpn inverse assumes that highest limb is non-zero + + Fp_model() {}; + Fp_model(const bigint &b); + Fp_model(const long x, const bool is_unsigned=false); + + void set_ulong(const unsigned long x); + + void mul_reduce(const bigint &other); + + void clear(); + + /* Return the standard (not Montgomery) representation of the + Field element's requivalence class. I.e. Fp(2).as_bigint() + would return bigint(2) */ + bigint as_bigint() const; + /* Return the last limb of the standard representation of the + field element. E.g. on 64-bit architectures Fp(123).as_ulong() + and Fp(2^64+123).as_ulong() would both return 123. */ + unsigned long as_ulong() const; + + bool operator==(const Fp_model& other) const; + bool operator!=(const Fp_model& other) const; + bool is_zero() const; + + void print() const; + + Fp_model& operator+=(const Fp_model& other); + Fp_model& operator-=(const Fp_model& other); + Fp_model& operator*=(const Fp_model& other); + Fp_model& operator^=(const unsigned long pow); + + template + Fp_model& operator^=(const bigint &pow); + + Fp_model operator+(const Fp_model& other) const; + Fp_model operator-(const Fp_model& other) const; + Fp_model operator*(const Fp_model& other) const; + Fp_model operator-() const; + Fp_model squared() const; + Fp_model& invert(); + Fp_model inverse() const; + Fp_model sqrt() const; // HAS TO BE A SQUARE (else does not terminate) + + Fp_model operator^(const unsigned long pow) const; + template + Fp_model operator^(const bigint &pow) const; + + static size_t size_in_bits() { return num_bits; } + static size_t capacity() { return num_bits - 1; } + static bigint field_char() { return modulus; } + + static Fp_model zero(); + static Fp_model one(); + static Fp_model random_element(); + + friend std::ostream& operator<< (std::ostream &out, const Fp_model &p); + friend std::istream& operator>> (std::istream &in, Fp_model &p); +}; + +#ifdef PROFILE_OP_COUNTS +template& modulus> +long long Fp_model::add_cnt = 0; + +template& modulus> +long long Fp_model::sub_cnt = 0; + +template& modulus> +long long Fp_model::mul_cnt = 0; + +template& modulus> +long long Fp_model::sqr_cnt = 0; + +template& modulus> +long long Fp_model::inv_cnt = 0; +#endif + +template& modulus> +size_t Fp_model::num_bits; + +template& modulus> +bigint Fp_model::euler; + +template& modulus> +size_t Fp_model::s; + +template& modulus> +bigint Fp_model::t; + +template& modulus> +bigint Fp_model::t_minus_1_over_2; + +template& modulus> +Fp_model Fp_model::nqr; + +template& modulus> +Fp_model Fp_model::nqr_to_t; + +template& modulus> +Fp_model Fp_model::multiplicative_generator; + +template& modulus> +Fp_model Fp_model::root_of_unity; + +template& modulus> +mp_limb_t Fp_model::inv; + +template& modulus> +bigint Fp_model::Rsquared; + +template& modulus> +bigint Fp_model::Rcubed; + +} // libsnark +#include "algebra/fields/fp.tcc" + +#endif // FP_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/algebra/fields/fp.tcc b/privacy/zsl/zsl/snark/libsnark/src/algebra/fields/fp.tcc new file mode 100644 index 0000000..35fd3ac --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/algebra/fields/fp.tcc @@ -0,0 +1,785 @@ +/** @file + ***************************************************************************** + Implementation of arithmetic in the finite field F[p], for prime p of fixed length. + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef FP_TCC_ +#define FP_TCC_ +#include +#include +#include + +#include "algebra/fields/fp_aux.tcc" +#include "algebra/fields/field_utils.hpp" + +namespace libsnark { + +template& modulus> +void Fp_model::mul_reduce(const bigint &other) +{ + /* stupid pre-processor tricks; beware */ +#if defined(__x86_64__) && defined(USE_ASM) + if (n == 3) + { // Use asm-optimized Comba multiplication and reduction + mp_limb_t res[2*n]; + mp_limb_t c0, c1, c2; + COMBA_3_BY_3_MUL(c0, c1, c2, res, this->mont_repr.data, other.data); + + mp_limb_t k; + mp_limb_t tmp1, tmp2, tmp3; + REDUCE_6_LIMB_PRODUCT(k, tmp1, tmp2, tmp3, inv, res, modulus.data); + + /* subtract t > mod */ + __asm__ + ("/* check for overflow */ \n\t" + MONT_CMP(16) + MONT_CMP(8) + MONT_CMP(0) + + "/* subtract mod if overflow */ \n\t" + "subtract%=: \n\t" + MONT_FIRSTSUB + MONT_NEXTSUB(8) + MONT_NEXTSUB(16) + "done%=: \n\t" + : + : [tmp] "r" (res+n), [M] "r" (modulus.data) + : "cc", "memory", "%rax"); + mpn_copyi(this->mont_repr.data, res+n, n); + } + else if (n == 4) + { // use asm-optimized "CIOS method" + + mp_limb_t tmp[n+1]; + mp_limb_t T0=0, T1=1, cy=2, u=3; // TODO: fix this + + __asm__ (MONT_PRECOMPUTE + MONT_FIRSTITER(1) + MONT_FIRSTITER(2) + MONT_FIRSTITER(3) + MONT_FINALIZE(3) + MONT_ITERFIRST(1) + MONT_ITERITER(1, 1) + MONT_ITERITER(1, 2) + MONT_ITERITER(1, 3) + MONT_FINALIZE(3) + MONT_ITERFIRST(2) + MONT_ITERITER(2, 1) + MONT_ITERITER(2, 2) + MONT_ITERITER(2, 3) + MONT_FINALIZE(3) + MONT_ITERFIRST(3) + MONT_ITERITER(3, 1) + MONT_ITERITER(3, 2) + MONT_ITERITER(3, 3) + MONT_FINALIZE(3) + "/* check for overflow */ \n\t" + MONT_CMP(24) + MONT_CMP(16) + MONT_CMP(8) + MONT_CMP(0) + + "/* subtract mod if overflow */ \n\t" + "subtract%=: \n\t" + MONT_FIRSTSUB + MONT_NEXTSUB(8) + MONT_NEXTSUB(16) + MONT_NEXTSUB(24) + "done%=: \n\t" + : + : [tmp] "r" (tmp), [A] "r" (this->mont_repr.data), [B] "r" (other.data), [inv] "r" (inv), [M] "r" (modulus.data), + [T0] "r" (T0), [T1] "r" (T1), [cy] "r" (cy), [u] "r" (u) + : "cc", "memory", "%rax", "%rdx" + ); + mpn_copyi(this->mont_repr.data, tmp, n); + } + else if (n == 5) + { // use asm-optimized "CIOS method" + + mp_limb_t tmp[n+1]; + mp_limb_t T0=0, T1=1, cy=2, u=3; // TODO: fix this + + __asm__ (MONT_PRECOMPUTE + MONT_FIRSTITER(1) + MONT_FIRSTITER(2) + MONT_FIRSTITER(3) + MONT_FIRSTITER(4) + MONT_FINALIZE(4) + MONT_ITERFIRST(1) + MONT_ITERITER(1, 1) + MONT_ITERITER(1, 2) + MONT_ITERITER(1, 3) + MONT_ITERITER(1, 4) + MONT_FINALIZE(4) + MONT_ITERFIRST(2) + MONT_ITERITER(2, 1) + MONT_ITERITER(2, 2) + MONT_ITERITER(2, 3) + MONT_ITERITER(2, 4) + MONT_FINALIZE(4) + MONT_ITERFIRST(3) + MONT_ITERITER(3, 1) + MONT_ITERITER(3, 2) + MONT_ITERITER(3, 3) + MONT_ITERITER(3, 4) + MONT_FINALIZE(4) + MONT_ITERFIRST(4) + MONT_ITERITER(4, 1) + MONT_ITERITER(4, 2) + MONT_ITERITER(4, 3) + MONT_ITERITER(4, 4) + MONT_FINALIZE(4) + "/* check for overflow */ \n\t" + MONT_CMP(32) + MONT_CMP(24) + MONT_CMP(16) + MONT_CMP(8) + MONT_CMP(0) + + "/* subtract mod if overflow */ \n\t" + "subtract%=: \n\t" + MONT_FIRSTSUB + MONT_NEXTSUB(8) + MONT_NEXTSUB(16) + MONT_NEXTSUB(24) + MONT_NEXTSUB(32) + "done%=: \n\t" + : + : [tmp] "r" (tmp), [A] "r" (this->mont_repr.data), [B] "r" (other.data), [inv] "r" (inv), [M] "r" (modulus.data), + [T0] "r" (T0), [T1] "r" (T1), [cy] "r" (cy), [u] "r" (u) + : "cc", "memory", "%rax", "%rdx" + ); + mpn_copyi(this->mont_repr.data, tmp, n); + } + else +#endif + { + mp_limb_t res[2*n]; + mpn_mul_n(res, this->mont_repr.data, other.data, n); + + /* + The Montgomery reduction here is based on Algorithm 14.32 in + Handbook of Applied Cryptography + . + */ + for (size_t i = 0; i < n; ++i) + { + mp_limb_t k = inv * res[i]; + /* calculate res = res + k * mod * b^i */ + mp_limb_t carryout = mpn_addmul_1(res+i, modulus.data, n, k); + carryout = mpn_add_1(res+n+i, res+n+i, n-i, carryout); + assert(carryout == 0); + } + + if (mpn_cmp(res+n, modulus.data, n) >= 0) + { + const mp_limb_t borrow = mpn_sub(res+n, res+n, n, modulus.data, n); + assert(borrow == 0); + } + + mpn_copyi(this->mont_repr.data, res+n, n); + } +} + +template& modulus> +Fp_model::Fp_model(const bigint &b) +{ + mpn_copyi(this->mont_repr.data, Rsquared.data, n); + mul_reduce(b); +} + +template& modulus> +Fp_model::Fp_model(const long x, const bool is_unsigned) +{ + if (is_unsigned || x >= 0) + { + this->mont_repr.data[0] = (mp_limb_t)x; + } + else + { + const mp_limb_t borrow = mpn_sub_1(this->mont_repr.data, modulus.data, n, (mp_limb_t)-x); + assert(borrow == 0); + } + + mul_reduce(Rsquared); +} + +template& modulus> +void Fp_model::set_ulong(const unsigned long x) +{ + this->mont_repr.clear(); + this->mont_repr.data[0] = x; + mul_reduce(Rsquared); +} + +template& modulus> +void Fp_model::clear() +{ + this->mont_repr.clear(); +} + +template& modulus> +bigint Fp_model::as_bigint() const +{ + bigint one; + one.clear(); + one.data[0] = 1; + + Fp_model res(*this); + res.mul_reduce(one); + + return (res.mont_repr); +} + +template& modulus> +unsigned long Fp_model::as_ulong() const +{ + return this->as_bigint().as_ulong(); +} + +template& modulus> +bool Fp_model::operator==(const Fp_model& other) const +{ + return (this->mont_repr == other.mont_repr); +} + +template& modulus> +bool Fp_model::operator!=(const Fp_model& other) const +{ + return (this->mont_repr != other.mont_repr); +} + +template& modulus> +bool Fp_model::is_zero() const +{ + return (this->mont_repr.is_zero()); // zero maps to zero +} + +template& modulus> +void Fp_model::print() const +{ + Fp_model tmp; + tmp.mont_repr.data[0] = 1; + tmp.mul_reduce(this->mont_repr); + + tmp.mont_repr.print(); +} + +template& modulus> +Fp_model Fp_model::zero() +{ + Fp_model res; + res.mont_repr.clear(); + return res; +} + +template& modulus> +Fp_model Fp_model::one() +{ + Fp_model res; + res.mont_repr.data[0] = 1; + res.mul_reduce(Rsquared); + return res; +} + +template& modulus> +Fp_model& Fp_model::operator+=(const Fp_model& other) +{ +#ifdef PROFILE_OP_COUNTS + this->add_cnt++; +#endif +#if defined(__x86_64__) && defined(USE_ASM) + if (n == 3) + { + __asm__ + ("/* perform bignum addition */ \n\t" + ADD_FIRSTADD + ADD_NEXTADD(8) + ADD_NEXTADD(16) + "/* if overflow: subtract */ \n\t" + "/* (tricky point: if A and B are in the range we do not need to do anything special for the possible carry flag) */ \n\t" + "jc subtract%= \n\t" + + "/* check for overflow */ \n\t" + ADD_CMP(16) + ADD_CMP(8) + ADD_CMP(0) + + "/* subtract mod if overflow */ \n\t" + "subtract%=: \n\t" + ADD_FIRSTSUB + ADD_NEXTSUB(8) + ADD_NEXTSUB(16) + "done%=: \n\t" + : + : [A] "r" (this->mont_repr.data), [B] "r" (other.mont_repr.data), [mod] "r" (modulus.data) + : "cc", "memory", "%rax"); + } + else if (n == 4) + { + __asm__ + ("/* perform bignum addition */ \n\t" + ADD_FIRSTADD + ADD_NEXTADD(8) + ADD_NEXTADD(16) + ADD_NEXTADD(24) + "/* if overflow: subtract */ \n\t" + "/* (tricky point: if A and B are in the range we do not need to do anything special for the possible carry flag) */ \n\t" + "jc subtract%= \n\t" + + "/* check for overflow */ \n\t" + ADD_CMP(24) + ADD_CMP(16) + ADD_CMP(8) + ADD_CMP(0) + + "/* subtract mod if overflow */ \n\t" + "subtract%=: \n\t" + ADD_FIRSTSUB + ADD_NEXTSUB(8) + ADD_NEXTSUB(16) + ADD_NEXTSUB(24) + "done%=: \n\t" + : + : [A] "r" (this->mont_repr.data), [B] "r" (other.mont_repr.data), [mod] "r" (modulus.data) + : "cc", "memory", "%rax"); + } + else if (n == 5) + { + __asm__ + ("/* perform bignum addition */ \n\t" + ADD_FIRSTADD + ADD_NEXTADD(8) + ADD_NEXTADD(16) + ADD_NEXTADD(24) + ADD_NEXTADD(32) + "/* if overflow: subtract */ \n\t" + "/* (tricky point: if A and B are in the range we do not need to do anything special for the possible carry flag) */ \n\t" + "jc subtract%= \n\t" + + "/* check for overflow */ \n\t" + ADD_CMP(32) + ADD_CMP(24) + ADD_CMP(16) + ADD_CMP(8) + ADD_CMP(0) + + "/* subtract mod if overflow */ \n\t" + "subtract%=: \n\t" + ADD_FIRSTSUB + ADD_NEXTSUB(8) + ADD_NEXTSUB(16) + ADD_NEXTSUB(24) + ADD_NEXTSUB(32) + "done%=: \n\t" + : + : [A] "r" (this->mont_repr.data), [B] "r" (other.mont_repr.data), [mod] "r" (modulus.data) + : "cc", "memory", "%rax"); + } + else +#endif + { + mp_limb_t scratch[n+1]; + const mp_limb_t carry = mpn_add_n(scratch, this->mont_repr.data, other.mont_repr.data, n); + scratch[n] = carry; + + if (carry || mpn_cmp(scratch, modulus.data, n) >= 0) + { + const mp_limb_t borrow = mpn_sub(scratch, scratch, n+1, modulus.data, n); + assert(borrow == 0); + } + + mpn_copyi(this->mont_repr.data, scratch, n); + } + + return *this; +} + +template& modulus> +Fp_model& Fp_model::operator-=(const Fp_model& other) +{ +#ifdef PROFILE_OP_COUNTS + this->sub_cnt++; +#endif +#if defined(__x86_64__) && defined(USE_ASM) + if (n == 3) + { + __asm__ + (SUB_FIRSTSUB + SUB_NEXTSUB(8) + SUB_NEXTSUB(16) + + "jnc done%=\n\t" + + SUB_FIRSTADD + SUB_NEXTADD(8) + SUB_NEXTADD(16) + + "done%=:\n\t" + : + : [A] "r" (this->mont_repr.data), [B] "r" (other.mont_repr.data), [mod] "r" (modulus.data) + : "cc", "memory", "%rax"); + } + else if (n == 4) + { + __asm__ + (SUB_FIRSTSUB + SUB_NEXTSUB(8) + SUB_NEXTSUB(16) + SUB_NEXTSUB(24) + + "jnc done%=\n\t" + + SUB_FIRSTADD + SUB_NEXTADD(8) + SUB_NEXTADD(16) + SUB_NEXTADD(24) + + "done%=:\n\t" + : + : [A] "r" (this->mont_repr.data), [B] "r" (other.mont_repr.data), [mod] "r" (modulus.data) + : "cc", "memory", "%rax"); + } + else if (n == 5) + { + __asm__ + (SUB_FIRSTSUB + SUB_NEXTSUB(8) + SUB_NEXTSUB(16) + SUB_NEXTSUB(24) + SUB_NEXTSUB(32) + + "jnc done%=\n\t" + + SUB_FIRSTADD + SUB_NEXTADD(8) + SUB_NEXTADD(16) + SUB_NEXTADD(24) + SUB_NEXTADD(32) + + "done%=:\n\t" + : + : [A] "r" (this->mont_repr.data), [B] "r" (other.mont_repr.data), [mod] "r" (modulus.data) + : "cc", "memory", "%rax"); + } + else +#endif + { + mp_limb_t scratch[n+1]; + if (mpn_cmp(this->mont_repr.data, other.mont_repr.data, n) < 0) + { + const mp_limb_t carry = mpn_add_n(scratch, this->mont_repr.data, modulus.data, n); + scratch[n] = carry; + } + else + { + mpn_copyi(scratch, this->mont_repr.data, n); + scratch[n] = 0; + } + + const mp_limb_t borrow = mpn_sub(scratch, scratch, n+1, other.mont_repr.data, n); + assert(borrow == 0); + + mpn_copyi(this->mont_repr.data, scratch, n); + } + return *this; +} + +template& modulus> +Fp_model& Fp_model::operator*=(const Fp_model& other) +{ +#ifdef PROFILE_OP_COUNTS + this->mul_cnt++; +#endif + + mul_reduce(other.mont_repr); + return *this; +} + +template& modulus> +Fp_model& Fp_model::operator^=(const unsigned long pow) +{ + (*this) = power >(*this, pow); + return (*this); +} + +template& modulus> +template +Fp_model& Fp_model::operator^=(const bigint &pow) +{ + (*this) = power, m>(*this, pow); + return (*this); +} + +template& modulus> +Fp_model Fp_model::operator+(const Fp_model& other) const +{ + Fp_model r(*this); + return (r += other); +} + +template& modulus> +Fp_model Fp_model::operator-(const Fp_model& other) const +{ + Fp_model r(*this); + return (r -= other); +} + +template& modulus> +Fp_model Fp_model::operator*(const Fp_model& other) const +{ + Fp_model r(*this); + return (r *= other); +} + +template& modulus> +Fp_model Fp_model::operator^(const unsigned long pow) const +{ + Fp_model r(*this); + return (r ^= pow); +} + +template& modulus> +template +Fp_model Fp_model::operator^(const bigint &pow) const +{ + Fp_model r(*this); + return (r ^= pow); +} + +template& modulus> +Fp_model Fp_model::operator-() const +{ +#ifdef PROFILE_OP_COUNTS + this->sub_cnt++; +#endif + + if (this->is_zero()) + { + return (*this); + } + else + { + Fp_model r; + mpn_sub_n(r.mont_repr.data, modulus.data, this->mont_repr.data, n); + return r; + } +} + +template& modulus> +Fp_model Fp_model::squared() const +{ +#ifdef PROFILE_OP_COUNTS + this->sqr_cnt++; + this->mul_cnt--; // zero out the upcoming mul +#endif + /* stupid pre-processor tricks; beware */ +#if defined(__x86_64__) && defined(USE_ASM) + if (n == 3) + { // use asm-optimized Comba squaring + mp_limb_t res[2*n]; + mp_limb_t c0, c1, c2; + COMBA_3_BY_3_SQR(c0, c1, c2, res, this->mont_repr.data); + + mp_limb_t k; + mp_limb_t tmp1, tmp2, tmp3; + REDUCE_6_LIMB_PRODUCT(k, tmp1, tmp2, tmp3, inv, res, modulus.data); + + /* subtract t > mod */ + __asm__ volatile + ("/* check for overflow */ \n\t" + MONT_CMP(16) + MONT_CMP(8) + MONT_CMP(0) + + "/* subtract mod if overflow */ \n\t" + "subtract%=: \n\t" + MONT_FIRSTSUB + MONT_NEXTSUB(8) + MONT_NEXTSUB(16) + "done%=: \n\t" + : + : [tmp] "r" (res+n), [M] "r" (modulus.data) + : "cc", "memory", "%rax"); + + Fp_model r; + mpn_copyi(r.mont_repr.data, res+n, n); + return r; + } + else +#endif + { + Fp_model r(*this); + return (r *= r); + } +} + +template& modulus> +Fp_model& Fp_model::invert() +{ +#ifdef PROFILE_OP_COUNTS + this->inv_cnt++; +#endif + + assert(!this->is_zero()); + + bigint g; /* gp should have room for vn = n limbs */ + + mp_limb_t s[n+1]; /* sp should have room for vn+1 limbs */ + mp_size_t sn; + + bigint v = modulus; // both source operands are destroyed by mpn_gcdext + + /* computes gcd(u, v) = g = u*s + v*t, so s*u will be 1 (mod v) */ + const mp_size_t gn = mpn_gcdext(g.data, s, &sn, this->mont_repr.data, n, v.data, n); + assert(gn == 1 && g.data[0] == 1); /* inverse exists */ + + mp_limb_t q; /* division result fits into q, as sn <= n+1 */ + /* sn < 0 indicates negative sn; will fix up later */ + + if (std::abs(sn) >= n) + { + /* if sn could require modulus reduction, do it here */ + mpn_tdiv_qr(&q, this->mont_repr.data, 0, s, std::abs(sn), modulus.data, n); + } + else + { + /* otherwise just copy it over */ + mpn_zero(this->mont_repr.data, n); + mpn_copyi(this->mont_repr.data, s, std::abs(sn)); + } + + /* fix up the negative sn */ + if (sn < 0) + { + const mp_limb_t borrow = mpn_sub_n(this->mont_repr.data, modulus.data, this->mont_repr.data, n); + assert(borrow == 0); + } + + mul_reduce(Rcubed); + return *this; +} + +template& modulus> +Fp_model Fp_model::inverse() const +{ + Fp_model r(*this); + return (r.invert()); +} + +template& modulus> +Fp_model Fp_model::random_element() /// returns random element of Fp_model +{ + /* note that as Montgomery representation is a bijection then + selecting a random element of {xR} is the same as selecting a + random element of {x} */ + Fp_model r; + do + { + r.mont_repr.randomize(); + + /* clear all bits higher than MSB of modulus */ + size_t bitno = GMP_NUMB_BITS * n - 1; + while (modulus.test_bit(bitno) == false) + { + const std::size_t part = bitno/GMP_NUMB_BITS; + const std::size_t bit = bitno - (GMP_NUMB_BITS*part); + + r.mont_repr.data[part] &= ~(1ul<= modulus -- repeat (rejection sampling) */ + while (mpn_cmp(r.mont_repr.data, modulus.data, n) >= 0); + + return r; +} + +template& modulus> +Fp_model Fp_model::sqrt() const +{ + Fp_model one = Fp_model::one(); + + size_t v = Fp_model::s; + Fp_model z = Fp_model::nqr_to_t; + Fp_model w = (*this)^Fp_model::t_minus_1_over_2; + Fp_model x = (*this) * w; + Fp_model b = x * w; // b = (*this)^t + +#if DEBUG + // check if square with euler's criterion + Fp_model check = b; + for (size_t i = 0; i < v-1; ++i) + { + check = check.squared(); + } + if (check != one) + { + assert(0); + } +#endif + + // compute square root with Tonelli--Shanks + // (does not terminate if not a square!) + + while (b != one) + { + size_t m = 0; + Fp_model b2m = b; + while (b2m != one) + { + /* invariant: b2m = b^(2^m) after entering this loop */ + b2m = b2m.squared(); + m += 1; + } + + int j = v-m-1; + w = z; + while (j > 0) + { + w = w.squared(); + --j; + } // w = z^2^(v-m-1) + + z = w.squared(); + b = b * z; + x = x * w; + v = m; + } + + return x; +} + +template& modulus> +std::ostream& operator<<(std::ostream &out, const Fp_model &p) +{ +#ifndef MONTGOMERY_OUTPUT + Fp_model tmp; + tmp.mont_repr.data[0] = 1; + tmp.mul_reduce(p.mont_repr); + out << tmp.mont_repr; +#else + out << p.mont_repr; +#endif + return out; +} + +template& modulus> +std::istream& operator>>(std::istream &in, Fp_model &p) +{ +#ifndef MONTGOMERY_OUTPUT + in >> p.mont_repr; + p.mul_reduce(Fp_model::Rsquared); +#else + in >> p.mont_repr; +#endif + return in; +} + +} // libsnark +#endif // FP_TCC_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/algebra/fields/fp12_2over3over2.hpp b/privacy/zsl/zsl/snark/libsnark/src/algebra/fields/fp12_2over3over2.hpp new file mode 100644 index 0000000..1de9d88 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/algebra/fields/fp12_2over3over2.hpp @@ -0,0 +1,116 @@ +/** @file + ***************************************************************************** + Declaration of arithmetic in the finite field F[((p^2)^3)^2]. + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef FP12_2OVER3OVER2_HPP_ +#define FP12_2OVER3OVER2_HPP_ +#include "algebra/fields/fp.hpp" +#include "algebra/fields/fp2.hpp" +#include "algebra/fields/fp6_3over2.hpp" +#include + +namespace libsnark { + +template& modulus> +class Fp12_2over3over2_model; + +template& modulus> +std::ostream& operator<<(std::ostream &, const Fp12_2over3over2_model &); + +template& modulus> +std::istream& operator>>(std::istream &, Fp12_2over3over2_model &); + +/** + * Arithmetic in the finite field F[((p^2)^3)^2]. + * + * Let p := modulus. This interface provides arithmetic for the extension field + * Fp12 = Fp6[W]/(W^2-V) where Fp6 = Fp2[V]/(V^3-non_residue) and non_residue is in Fp2 + * + * ASSUMPTION: p = 1 (mod 6) + */ +template& modulus> +class Fp12_2over3over2_model { +public: + typedef Fp_model my_Fp; + typedef Fp2_model my_Fp2; + typedef Fp6_3over2_model my_Fp6; + + static Fp2_model non_residue; + static Fp2_model Frobenius_coeffs_c1[12]; // non_residue^((modulus^i-1)/6) for i=0,...,11 + + my_Fp6 c0, c1; + Fp12_2over3over2_model() {}; + Fp12_2over3over2_model(const my_Fp6& c0, const my_Fp6& c1) : c0(c0), c1(c1) {}; + + void clear() { c0.clear(); c1.clear(); } + void print() const { printf("c0/c1:\n"); c0.print(); c1.print(); } + + static Fp12_2over3over2_model zero(); + static Fp12_2over3over2_model one(); + static Fp12_2over3over2_model random_element(); + + bool is_zero() const { return c0.is_zero() && c1.is_zero(); } + bool operator==(const Fp12_2over3over2_model &other) const; + bool operator!=(const Fp12_2over3over2_model &other) const; + + Fp12_2over3over2_model operator+(const Fp12_2over3over2_model &other) const; + Fp12_2over3over2_model operator-(const Fp12_2over3over2_model &other) const; + Fp12_2over3over2_model operator*(const Fp12_2over3over2_model &other) const; + Fp12_2over3over2_model operator-() const; + Fp12_2over3over2_model squared() const; // default is squared_complex + Fp12_2over3over2_model squared_karatsuba() const; + Fp12_2over3over2_model squared_complex() const; + Fp12_2over3over2_model inverse() const; + Fp12_2over3over2_model Frobenius_map(unsigned long power) const; + Fp12_2over3over2_model unitary_inverse() const; + Fp12_2over3over2_model cyclotomic_squared() const; + + Fp12_2over3over2_model mul_by_024(const my_Fp2 &ell_0, const my_Fp2 &ell_VW, const my_Fp2 &ell_VV) const; + + static my_Fp6 mul_by_non_residue(const my_Fp6 &elt); + + template + Fp12_2over3over2_model cyclotomic_exp(const bigint &exponent) const; + + static bigint base_field_char() { return modulus; } + static size_t extension_degree() { return 12; } + + friend std::ostream& operator<< (std::ostream &out, const Fp12_2over3over2_model &el); + friend std::istream& operator>> (std::istream &in, Fp12_2over3over2_model &el); +}; + +template& modulus> +std::ostream& operator<<(std::ostream& out, const std::vector > &v); + +template& modulus> +std::istream& operator>>(std::istream& in, std::vector > &v); + +template& modulus> +Fp12_2over3over2_model operator*(const Fp_model &lhs, const Fp12_2over3over2_model &rhs); + +template& modulus> +Fp12_2over3over2_model operator*(const Fp2_model &lhs, const Fp12_2over3over2_model &rhs); + +template& modulus> +Fp12_2over3over2_model operator*(const Fp6_3over2_model &lhs, const Fp12_2over3over2_model &rhs); + +template& modulus, mp_size_t m> +Fp12_2over3over2_model operator^(const Fp12_2over3over2_model &self, const bigint &exponent); + +template& modulus, mp_size_t m, const bigint& exp_modulus> +Fp12_2over3over2_model operator^(const Fp12_2over3over2_model &self, const Fp_model &exponent); + +template& modulus> +Fp2_model Fp12_2over3over2_model::non_residue; + +template& modulus> +Fp2_model Fp12_2over3over2_model::Frobenius_coeffs_c1[12]; + +} // libsnark +#include "algebra/fields/fp12_2over3over2.tcc" +#endif // FP12_2OVER3OVER2_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/algebra/fields/fp12_2over3over2.tcc b/privacy/zsl/zsl/snark/libsnark/src/algebra/fields/fp12_2over3over2.tcc new file mode 100644 index 0000000..2fbc0b6 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/algebra/fields/fp12_2over3over2.tcc @@ -0,0 +1,412 @@ +/** @file + ***************************************************************************** + Implementation of arithmetic in the finite field F[((p^2)^3)^2]. + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef FP12_2OVER3OVER2_TCC_ +#define FP12_2OVER3OVER2_TCC_ + +namespace libsnark { + +template& modulus> +Fp6_3over2_model Fp12_2over3over2_model::mul_by_non_residue(const Fp6_3over2_model &elt) +{ + return Fp6_3over2_model(non_residue * elt.c2, elt.c0, elt.c1); +} + +template& modulus> +Fp12_2over3over2_model Fp12_2over3over2_model::zero() +{ + return Fp12_2over3over2_model(my_Fp6::zero(), my_Fp6::zero()); +} + +template& modulus> +Fp12_2over3over2_model Fp12_2over3over2_model::one() +{ + return Fp12_2over3over2_model(my_Fp6::one(), my_Fp6::zero()); +} + +template& modulus> +Fp12_2over3over2_model Fp12_2over3over2_model::random_element() +{ + Fp12_2over3over2_model r; + r.c0 = my_Fp6::random_element(); + r.c1 = my_Fp6::random_element(); + + return r; +} + +template& modulus> +bool Fp12_2over3over2_model::operator==(const Fp12_2over3over2_model &other) const +{ + return (this->c0 == other.c0 && this->c1 == other.c1); +} + +template& modulus> +bool Fp12_2over3over2_model::operator!=(const Fp12_2over3over2_model &other) const +{ + return !(operator==(other)); +} + +template& modulus> +Fp12_2over3over2_model Fp12_2over3over2_model::operator+(const Fp12_2over3over2_model &other) const +{ + return Fp12_2over3over2_model(this->c0 + other.c0, + this->c1 + other.c1); +} + +template& modulus> +Fp12_2over3over2_model Fp12_2over3over2_model::operator-(const Fp12_2over3over2_model &other) const +{ + return Fp12_2over3over2_model(this->c0 - other.c0, + this->c1 - other.c1); +} + +template& modulus> +Fp12_2over3over2_model operator*(const Fp_model &lhs, const Fp12_2over3over2_model &rhs) +{ + return Fp12_2over3over2_model(lhs*rhs.c0, + lhs*rhs.c1); +} + +template& modulus> +Fp12_2over3over2_model operator*(const Fp2_model &lhs, const Fp12_2over3over2_model &rhs) +{ + return Fp12_2over3over2_model(lhs*rhs.c0, + lhs*rhs.c1); +} + +template& modulus> +Fp12_2over3over2_model operator*(const Fp6_3over2_model &lhs, const Fp12_2over3over2_model &rhs) +{ + return Fp12_2over3over2_model(lhs*rhs.c0, + lhs*rhs.c1); +} + +template& modulus> +Fp12_2over3over2_model Fp12_2over3over2_model::operator*(const Fp12_2over3over2_model &other) const +{ + /* Devegili OhEig Scott Dahab --- Multiplication and Squaring on Pairing-Friendly Fields.pdf; Section 3 (Karatsuba) */ + + const my_Fp6 &A = other.c0, &B = other.c1, + &a = this->c0, &b = this->c1; + const my_Fp6 aA = a * A; + const my_Fp6 bB = b * B; + + return Fp12_2over3over2_model(aA + Fp12_2over3over2_model::mul_by_non_residue(bB), + (a + b)*(A+B) - aA - bB); +} + +template& modulus> +Fp12_2over3over2_model Fp12_2over3over2_model::operator-() const +{ + return Fp12_2over3over2_model(-this->c0, + -this->c1); +} + +template& modulus> +Fp12_2over3over2_model Fp12_2over3over2_model::squared() const +{ + return squared_complex(); +} + +template& modulus> +Fp12_2over3over2_model Fp12_2over3over2_model::squared_karatsuba() const +{ + /* Devegili OhEig Scott Dahab --- Multiplication and Squaring on Pairing-Friendly Fields.pdf; Section 3 (Karatsuba squaring) */ + + const my_Fp6 &a = this->c0, &b = this->c1; + const my_Fp6 asq = a.squared(); + const my_Fp6 bsq = b.squared(); + + return Fp12_2over3over2_model(asq + Fp12_2over3over2_model::mul_by_non_residue(bsq), + (a + b).squared() - asq - bsq); +} + +template& modulus> +Fp12_2over3over2_model Fp12_2over3over2_model::squared_complex() const +{ + /* Devegili OhEig Scott Dahab --- Multiplication and Squaring on Pairing-Friendly Fields.pdf; Section 3 (Complex squaring) */ + + const my_Fp6 &a = this->c0, &b = this->c1; + const my_Fp6 ab = a * b; + + return Fp12_2over3over2_model((a + b) * (a + Fp12_2over3over2_model::mul_by_non_residue(b)) - ab - Fp12_2over3over2_model::mul_by_non_residue(ab), + ab + ab); +} + +template& modulus> +Fp12_2over3over2_model Fp12_2over3over2_model::inverse() const +{ + /* From "High-Speed Software Implementation of the Optimal Ate Pairing over Barreto-Naehrig Curves"; Algorithm 8 */ + + const my_Fp6 &a = this->c0, &b = this->c1; + const my_Fp6 t0 = a.squared(); + const my_Fp6 t1 = b.squared(); + const my_Fp6 t2 = t0 - Fp12_2over3over2_model::mul_by_non_residue(t1); + const my_Fp6 t3 = t2.inverse(); + const my_Fp6 c0 = a * t3; + const my_Fp6 c1 = - (b * t3); + + return Fp12_2over3over2_model(c0, c1); +} + +template& modulus> +Fp12_2over3over2_model Fp12_2over3over2_model::Frobenius_map(unsigned long power) const +{ + return Fp12_2over3over2_model(c0.Frobenius_map(power), + Frobenius_coeffs_c1[power % 12] * c1.Frobenius_map(power)); +} + +template& modulus> +Fp12_2over3over2_model Fp12_2over3over2_model::unitary_inverse() const +{ + return Fp12_2over3over2_model(this->c0, + -this->c1); +} + +template& modulus> +Fp12_2over3over2_model Fp12_2over3over2_model::cyclotomic_squared() const +{ + /* OLD: naive implementation + return (*this).squared(); + */ + my_Fp2 z0 = this->c0.c0; + my_Fp2 z4 = this->c0.c1; + my_Fp2 z3 = this->c0.c2; + my_Fp2 z2 = this->c1.c0; + my_Fp2 z1 = this->c1.c1; + my_Fp2 z5 = this->c1.c2; + + my_Fp2 t0, t1, t2, t3, t4, t5, tmp; + + // t0 + t1*y = (z0 + z1*y)^2 = a^2 + tmp = z0 * z1; + t0 = (z0 + z1) * (z0 + my_Fp6::non_residue * z1) - tmp - my_Fp6::non_residue * tmp; + t1 = tmp + tmp; + // t2 + t3*y = (z2 + z3*y)^2 = b^2 + tmp = z2 * z3; + t2 = (z2 + z3) * (z2 + my_Fp6::non_residue * z3) - tmp - my_Fp6::non_residue * tmp; + t3 = tmp + tmp; + // t4 + t5*y = (z4 + z5*y)^2 = c^2 + tmp = z4 * z5; + t4 = (z4 + z5) * (z4 + my_Fp6::non_residue * z5) - tmp - my_Fp6::non_residue * tmp; + t5 = tmp + tmp; + + // for A + + // z0 = 3 * t0 - 2 * z0 + z0 = t0 - z0; + z0 = z0 + z0; + z0 = z0 + t0; + // z1 = 3 * t1 + 2 * z1 + z1 = t1 + z1; + z1 = z1 + z1; + z1 = z1 + t1; + + // for B + + // z2 = 3 * (xi * t5) + 2 * z2 + tmp = my_Fp6::non_residue * t5; + z2 = tmp + z2; + z2 = z2 + z2; + z2 = z2 + tmp; + + // z3 = 3 * t4 - 2 * z3 + z3 = t4 - z3; + z3 = z3 + z3; + z3 = z3 + t4; + + // for C + + // z4 = 3 * t2 - 2 * z4 + z4 = t2 - z4; + z4 = z4 + z4; + z4 = z4 + t2; + + // z5 = 3 * t3 + 2 * z5 + z5 = t3 + z5; + z5 = z5 + z5; + z5 = z5 + t3; + + return Fp12_2over3over2_model(my_Fp6(z0,z4,z3),my_Fp6(z2,z1,z5)); +} + +template& modulus> +Fp12_2over3over2_model Fp12_2over3over2_model::mul_by_024(const Fp2_model &ell_0, + const Fp2_model &ell_VW, + const Fp2_model &ell_VV) const +{ + /* OLD: naive implementation + Fp12_2over3over2_model a(my_Fp6(ell_0, my_Fp2::zero(), ell_VV), + my_Fp6(my_Fp2::zero(), ell_VW, my_Fp2::zero())); + + return (*this) * a; + */ + my_Fp2 z0 = this->c0.c0; + my_Fp2 z1 = this->c0.c1; + my_Fp2 z2 = this->c0.c2; + my_Fp2 z3 = this->c1.c0; + my_Fp2 z4 = this->c1.c1; + my_Fp2 z5 = this->c1.c2; + + my_Fp2 x0 = ell_0; + my_Fp2 x2 = ell_VV; + my_Fp2 x4 = ell_VW; + + my_Fp2 t0, t1, t2, s0, T3, T4, D0, D2, D4, S1; + + D0 = z0 * x0; + D2 = z2 * x2; + D4 = z4 * x4; + t2 = z0 + z4; + t1 = z0 + z2; + s0 = z1 + z3 + z5; + + // For z.a_.a_ = z0. + S1 = z1 * x2; + T3 = S1 + D4; + T4 = my_Fp6::non_residue * T3 + D0; + z0 = T4; + + // For z.a_.b_ = z1 + T3 = z5 * x4; + S1 = S1 + T3; + T3 = T3 + D2; + T4 = my_Fp6::non_residue * T3; + T3 = z1 * x0; + S1 = S1 + T3; + T4 = T4 + T3; + z1 = T4; + + // For z.a_.c_ = z2 + t0 = x0 + x2; + T3 = t1 * t0 - D0 - D2; + T4 = z3 * x4; + S1 = S1 + T4; + T3 = T3 + T4; + + // For z.b_.a_ = z3 (z3 needs z2) + t0 = z2 + z4; + z2 = T3; + t1 = x2 + x4; + T3 = t0 * t1 - D2 - D4; + T4 = my_Fp6::non_residue * T3; + T3 = z3 * x0; + S1 = S1 + T3; + T4 = T4 + T3; + z3 = T4; + + // For z.b_.b_ = z4 + T3 = z5 * x2; + S1 = S1 + T3; + T4 = my_Fp6::non_residue * T3; + t0 = x0 + x4; + T3 = t2 * t0 - D0 - D4; + T4 = T4 + T3; + z4 = T4; + + // For z.b_.c_ = z5. + t0 = x0 + x2 + x4; + T3 = s0 * t0 - S1; + z5 = T3; + + return Fp12_2over3over2_model(my_Fp6(z0,z1,z2),my_Fp6(z3,z4,z5)); + +} + +template& modulus, mp_size_t m> +Fp12_2over3over2_model operator^(const Fp12_2over3over2_model &self, const bigint &exponent) +{ + return power >(self, exponent); +} + +template& modulus, mp_size_t m, const bigint& exp_modulus> +Fp12_2over3over2_model operator^(const Fp12_2over3over2_model &self, const Fp_model &exponent) +{ + return self^(exponent.as_bigint()); +} + + +template& modulus> +template +Fp12_2over3over2_model Fp12_2over3over2_model::cyclotomic_exp(const bigint &exponent) const +{ + Fp12_2over3over2_model res = Fp12_2over3over2_model::one(); + + bool found_one = false; + for (long i = m-1; i >= 0; --i) + { + for (long j = GMP_NUMB_BITS - 1; j >= 0; --j) + { + if (found_one) + { + res = res.cyclotomic_squared(); + } + + if (exponent.data[i] & (1ul<& modulus> +std::ostream& operator<<(std::ostream &out, const Fp12_2over3over2_model &el) +{ + out << el.c0 << OUTPUT_SEPARATOR << el.c1; + return out; +} + +template& modulus> +std::istream& operator>>(std::istream &in, Fp12_2over3over2_model &el) +{ + in >> el.c0 >> el.c1; + return in; +} + +template& modulus> +std::ostream& operator<<(std::ostream& out, const std::vector > &v) +{ + out << v.size() << "\n"; + for (const Fp12_2over3over2_model& t : v) + { + out << t << OUTPUT_NEWLINE; + } + + return out; +} + +template& modulus> +std::istream& operator>>(std::istream& in, std::vector > &v) +{ + v.clear(); + + size_t s; + in >> s; + + char b; + in.read(&b, 1); + + v.reserve(s); + + for (size_t i = 0; i < s; ++i) + { + Fp12_2over3over2_model el; + in >> el; + v.emplace_back(el); + } + + return in; +} + +} // libsnark +#endif // FP12_2OVER3OVER2_TCC_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/algebra/fields/fp2.hpp b/privacy/zsl/zsl/snark/libsnark/src/algebra/fields/fp2.hpp new file mode 100644 index 0000000..7624779 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/algebra/fields/fp2.hpp @@ -0,0 +1,120 @@ +/** @file + ***************************************************************************** + Implementation of arithmetic in the finite field F[p^2]. + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef FP2_HPP_ +#define FP2_HPP_ +#include "algebra/fields/fp.hpp" +#include + +namespace libsnark { + +template& modulus> +class Fp2_model; + +template& modulus> +std::ostream& operator<<(std::ostream &, const Fp2_model &); + +template& modulus> +std::istream& operator>>(std::istream &, Fp2_model &); + +/** + * Arithmetic in the field F[p^2]. + * + * Let p := modulus. This interface provides arithmetic for the extension field + * Fp2 = Fp[U]/(U^2-non_residue), where non_residue is in Fp. + * + * ASSUMPTION: p = 1 (mod 6) + */ +template& modulus> +class Fp2_model { +public: + typedef Fp_model my_Fp; + + static bigint<2*n> euler; // (modulus^2-1)/2 + static size_t s; // modulus^2 = 2^s * t + 1 + static bigint<2*n> t; // with t odd + static bigint<2*n> t_minus_1_over_2; // (t-1)/2 + static my_Fp non_residue; // X^4-non_residue irreducible over Fp; used for constructing Fp2 = Fp[X] / (X^2 - non_residue) + static Fp2_model nqr; // a quadratic nonresidue in Fp2 + static Fp2_model nqr_to_t; // nqr^t + static my_Fp Frobenius_coeffs_c1[2]; // non_residue^((modulus^i-1)/2) for i=0,1 + + my_Fp c0, c1; + Fp2_model() {}; + Fp2_model(const my_Fp& c0, const my_Fp& c1) : c0(c0), c1(c1) {}; + + void clear() { c0.clear(); c1.clear(); } + void print() const { printf("c0/c1:\n"); c0.print(); c1.print(); } + + static Fp2_model zero(); + static Fp2_model one(); + static Fp2_model random_element(); + + bool is_zero() const { return c0.is_zero() && c1.is_zero(); } + bool operator==(const Fp2_model &other) const; + bool operator!=(const Fp2_model &other) const; + + Fp2_model operator+(const Fp2_model &other) const; + Fp2_model operator-(const Fp2_model &other) const; + Fp2_model operator*(const Fp2_model &other) const; + Fp2_model operator-() const; + Fp2_model squared() const; // default is squared_complex + Fp2_model inverse() const; + Fp2_model Frobenius_map(unsigned long power) const; + Fp2_model sqrt() const; // HAS TO BE A SQUARE (else does not terminate) + Fp2_model squared_karatsuba() const; + Fp2_model squared_complex() const; + + template + Fp2_model operator^(const bigint &other) const; + + static size_t size_in_bits() { return 2*my_Fp::size_in_bits(); } + static bigint base_field_char() { return modulus; } + + friend std::ostream& operator<< (std::ostream &out, const Fp2_model &el); + friend std::istream& operator>> (std::istream &in, Fp2_model &el); +}; + +template& modulus> +std::ostream& operator<<(std::ostream& out, const std::vector > &v); + +template& modulus> +std::istream& operator>>(std::istream& in, std::vector > &v); + +template& modulus> +Fp2_model operator*(const Fp_model &lhs, const Fp2_model &rhs); + +template& modulus> +bigint<2*n> Fp2_model::euler; + +template& modulus> +size_t Fp2_model::s; + +template& modulus> +bigint<2*n> Fp2_model::t; + +template& modulus> +bigint<2*n> Fp2_model::t_minus_1_over_2; + +template& modulus> +Fp_model Fp2_model::non_residue; + +template& modulus> +Fp2_model Fp2_model::nqr; + +template& modulus> +Fp2_model Fp2_model::nqr_to_t; + +template& modulus> +Fp_model Fp2_model::Frobenius_coeffs_c1[2]; + +} // libsnark +#include "algebra/fields/fp2.tcc" + +#endif // FP2_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/algebra/fields/fp2.tcc b/privacy/zsl/zsl/snark/libsnark/src/algebra/fields/fp2.tcc new file mode 100644 index 0000000..5c2397e --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/algebra/fields/fp2.tcc @@ -0,0 +1,257 @@ +/** @file + ***************************************************************************** + Implementation of arithmetic in the finite field F[p^2]. + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef FP2_TCC_ +#define FP2_TCC_ + +#include "algebra/fields/field_utils.hpp" + +namespace libsnark { + +template& modulus> +Fp2_model Fp2_model::zero() +{ + return Fp2_model(my_Fp::zero(), my_Fp::zero()); +} + +template& modulus> +Fp2_model Fp2_model::one() +{ + return Fp2_model(my_Fp::one(), my_Fp::zero()); +} + +template& modulus> +Fp2_model Fp2_model::random_element() +{ + Fp2_model r; + r.c0 = my_Fp::random_element(); + r.c1 = my_Fp::random_element(); + + return r; +} + +template& modulus> +bool Fp2_model::operator==(const Fp2_model &other) const +{ + return (this->c0 == other.c0 && this->c1 == other.c1); +} + +template& modulus> +bool Fp2_model::operator!=(const Fp2_model &other) const +{ + return !(operator==(other)); +} + +template& modulus> +Fp2_model Fp2_model::operator+(const Fp2_model &other) const +{ + return Fp2_model(this->c0 + other.c0, + this->c1 + other.c1); +} + +template& modulus> +Fp2_model Fp2_model::operator-(const Fp2_model &other) const +{ + return Fp2_model(this->c0 - other.c0, + this->c1 - other.c1); +} + +template& modulus> +Fp2_model operator*(const Fp_model &lhs, const Fp2_model &rhs) +{ + return Fp2_model(lhs*rhs.c0, + lhs*rhs.c1); +} + +template& modulus> +Fp2_model Fp2_model::operator*(const Fp2_model &other) const +{ + /* Devegili OhEig Scott Dahab --- Multiplication and Squaring on Pairing-Friendly Fields.pdf; Section 3 (Karatsuba) */ + const my_Fp + &A = other.c0, &B = other.c1, + &a = this->c0, &b = this->c1; + const my_Fp aA = a * A; + const my_Fp bB = b * B; + + return Fp2_model(aA + non_residue * bB, + (a + b)*(A+B) - aA - bB); +} + +template& modulus> +Fp2_model Fp2_model::operator-() const +{ + return Fp2_model(-this->c0, + -this->c1); +} + +template& modulus> +Fp2_model Fp2_model::squared() const +{ + return squared_complex(); +} + +template& modulus> +Fp2_model Fp2_model::squared_karatsuba() const +{ + /* Devegili OhEig Scott Dahab --- Multiplication and Squaring on Pairing-Friendly Fields.pdf; Section 3 (Karatsuba squaring) */ + const my_Fp &a = this->c0, &b = this->c1; + const my_Fp asq = a.squared(); + const my_Fp bsq = b.squared(); + + return Fp2_model(asq + non_residue * bsq, + (a + b).squared() - asq - bsq); +} + +template& modulus> +Fp2_model Fp2_model::squared_complex() const +{ + /* Devegili OhEig Scott Dahab --- Multiplication and Squaring on Pairing-Friendly Fields.pdf; Section 3 (Complex squaring) */ + const my_Fp &a = this->c0, &b = this->c1; + const my_Fp ab = a * b; + + return Fp2_model((a + b) * (a + non_residue * b) - ab - non_residue * ab, + ab + ab); +} + +template& modulus> +Fp2_model Fp2_model::inverse() const +{ + const my_Fp &a = this->c0, &b = this->c1; + + /* From "High-Speed Software Implementation of the Optimal Ate Pairing over Barreto-Naehrig Curves"; Algorithm 8 */ + const my_Fp t0 = a.squared(); + const my_Fp t1 = b.squared(); + const my_Fp t2 = t0 - non_residue * t1; + const my_Fp t3 = t2.inverse(); + const my_Fp c0 = a * t3; + const my_Fp c1 = - (b * t3); + + return Fp2_model(c0, c1); +} + +template& modulus> +Fp2_model Fp2_model::Frobenius_map(unsigned long power) const +{ + return Fp2_model(c0, + Frobenius_coeffs_c1[power % 2] * c1); +} + +template& modulus> +Fp2_model Fp2_model::sqrt() const +{ + Fp2_model one = Fp2_model::one(); + + size_t v = Fp2_model::s; + Fp2_model z = Fp2_model::nqr_to_t; + Fp2_model w = (*this)^Fp2_model::t_minus_1_over_2; + Fp2_model x = (*this) * w; + Fp2_model b = x * w; // b = (*this)^t + +#if DEBUG + // check if square with euler's criterion + Fp2_model check = b; + for (size_t i = 0; i < v-1; ++i) + { + check = check.squared(); + } + if (check != one) + { + assert(0); + } +#endif + + // compute square root with Tonelli--Shanks + // (does not terminate if not a square!) + + while (b != one) + { + size_t m = 0; + Fp2_model b2m = b; + while (b2m != one) + { + /* invariant: b2m = b^(2^m) after entering this loop */ + b2m = b2m.squared(); + m += 1; + } + + int j = v-m-1; + w = z; + while (j > 0) + { + w = w.squared(); + --j; + } // w = z^2^(v-m-1) + + z = w.squared(); + b = b * z; + x = x * w; + v = m; + } + + return x; +} + +template& modulus> +template +Fp2_model Fp2_model::operator^(const bigint &pow) const +{ + return power, m>(*this, pow); +} + +template& modulus> +std::ostream& operator<<(std::ostream &out, const Fp2_model &el) +{ + out << el.c0 << OUTPUT_SEPARATOR << el.c1; + return out; +} + +template& modulus> +std::istream& operator>>(std::istream &in, Fp2_model &el) +{ + in >> el.c0 >> el.c1; + return in; +} + +template& modulus> +std::ostream& operator<<(std::ostream& out, const std::vector > &v) +{ + out << v.size() << "\n"; + for (const Fp2_model& t : v) + { + out << t << OUTPUT_NEWLINE; + } + + return out; +} + +template& modulus> +std::istream& operator>>(std::istream& in, std::vector > &v) +{ + v.clear(); + + size_t s; + in >> s; + + char b; + in.read(&b, 1); + + v.reserve(s); + + for (size_t i = 0; i < s; ++i) + { + Fp2_model el; + in >> el; + v.emplace_back(el); + } + + return in; +} + +} // libsnark +#endif // FP2_TCC_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/algebra/fields/fp3.hpp b/privacy/zsl/zsl/snark/libsnark/src/algebra/fields/fp3.hpp new file mode 100644 index 0000000..53b178a --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/algebra/fields/fp3.hpp @@ -0,0 +1,122 @@ +/** @file + ***************************************************************************** + Declaration of arithmetic in the finite field F[p^3]. + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef FP3_HPP_ +#define FP3_HPP_ +#include "algebra/fields/fp.hpp" +#include + +namespace libsnark { + +template& modulus> +class Fp3_model; + +template& modulus> +std::ostream& operator<<(std::ostream &, const Fp3_model &); + +template& modulus> +std::istream& operator>>(std::istream &, Fp3_model &); + +/** + * Arithmetic in the field F[p^3]. + * + * Let p := modulus. This interface provides arithmetic for the extension field + * Fp3 = Fp[U]/(U^3-non_residue), where non_residue is in Fp. + * + * ASSUMPTION: p = 1 (mod 6) + */ +template& modulus> +class Fp3_model { +public: + typedef Fp_model my_Fp; + + static bigint<3*n> euler; // (modulus^3-1)/2 + static size_t s; // modulus^3 = 2^s * t + 1 + static bigint<3*n> t; // with t odd + static bigint<3*n> t_minus_1_over_2; // (t-1)/2 + static my_Fp non_residue; // X^6-non_residue irreducible over Fp; used for constructing Fp3 = Fp[X] / (X^3 - non_residue) + static Fp3_model nqr; // a quadratic nonresidue in Fp3 + static Fp3_model nqr_to_t; // nqr^t + static my_Fp Frobenius_coeffs_c1[3]; // non_residue^((modulus^i-1)/3) for i=0,1,2 + static my_Fp Frobenius_coeffs_c2[3]; // non_residue^((2*modulus^i-2)/3) for i=0,1,2 + + my_Fp c0, c1, c2; + Fp3_model() {}; + Fp3_model(const my_Fp& c0, const my_Fp& c1, const my_Fp& c2) : c0(c0), c1(c1), c2(c2) {}; + + void clear() { c0.clear(); c1.clear(); c2.clear(); } + void print() const { printf("c0/c1/c2:\n"); c0.print(); c1.print(); c2.print(); } + + static Fp3_model zero(); + static Fp3_model one(); + static Fp3_model random_element(); + + bool is_zero() const { return c0.is_zero() && c1.is_zero() && c2.is_zero(); } + bool operator==(const Fp3_model &other) const; + bool operator!=(const Fp3_model &other) const; + + Fp3_model operator+(const Fp3_model &other) const; + Fp3_model operator-(const Fp3_model &other) const; + Fp3_model operator*(const Fp3_model &other) const; + Fp3_model operator-() const; + Fp3_model squared() const; + Fp3_model inverse() const; + Fp3_model Frobenius_map(unsigned long power) const; + Fp3_model sqrt() const; // HAS TO BE A SQUARE (else does not terminate) + + template + Fp3_model operator^(const bigint &other) const; + + static size_t size_in_bits() { return 3*my_Fp::size_in_bits(); } + static bigint base_field_char() { return modulus; } + + friend std::ostream& operator<< (std::ostream &out, const Fp3_model &el); + friend std::istream& operator>> (std::istream &in, Fp3_model &el); +}; + +template& modulus> +std::ostream& operator<<(std::ostream& out, const std::vector > &v); + +template& modulus> +std::istream& operator>>(std::istream& in, std::vector > &v); + +template& modulus> +Fp3_model operator*(const Fp_model &lhs, const Fp3_model &rhs); + +template& modulus> +bigint<3*n> Fp3_model::euler; + +template& modulus> +size_t Fp3_model::s; + +template& modulus> +bigint<3*n> Fp3_model::t; + +template& modulus> +bigint<3*n> Fp3_model::t_minus_1_over_2; + +template& modulus> +Fp_model Fp3_model::non_residue; + +template& modulus> +Fp3_model Fp3_model::nqr; + +template& modulus> +Fp3_model Fp3_model::nqr_to_t; + +template& modulus> +Fp_model Fp3_model::Frobenius_coeffs_c1[3]; + +template& modulus> +Fp_model Fp3_model::Frobenius_coeffs_c2[3]; + +} // libsnark +#include "algebra/fields/fp3.tcc" + +#endif // FP3_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/algebra/fields/fp3.tcc b/privacy/zsl/zsl/snark/libsnark/src/algebra/fields/fp3.tcc new file mode 100644 index 0000000..590a2a9 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/algebra/fields/fp3.tcc @@ -0,0 +1,259 @@ +/** @file + ***************************************************************************** + Implementation of arithmetic in the finite field F[p^3]. + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef FP3_TCC_ +#define FP3_TCC_ + +#include "algebra/fields/field_utils.hpp" + +namespace libsnark { + +template& modulus> +Fp3_model Fp3_model::zero() +{ + return Fp3_model(my_Fp::zero(), my_Fp::zero(), my_Fp::zero()); +} + +template& modulus> +Fp3_model Fp3_model::one() +{ + return Fp3_model(my_Fp::one(), my_Fp::zero(), my_Fp::zero()); +} + +template& modulus> +Fp3_model Fp3_model::random_element() +{ + Fp3_model r; + r.c0 = my_Fp::random_element(); + r.c1 = my_Fp::random_element(); + r.c2 = my_Fp::random_element(); + + return r; +} + +template& modulus> +bool Fp3_model::operator==(const Fp3_model &other) const +{ + return (this->c0 == other.c0 && this->c1 == other.c1 && this->c2 == other.c2); +} + +template& modulus> +bool Fp3_model::operator!=(const Fp3_model &other) const +{ + return !(operator==(other)); +} + +template& modulus> +Fp3_model Fp3_model::operator+(const Fp3_model &other) const +{ + return Fp3_model(this->c0 + other.c0, + this->c1 + other.c1, + this->c2 + other.c2); +} + +template& modulus> +Fp3_model Fp3_model::operator-(const Fp3_model &other) const +{ + return Fp3_model(this->c0 - other.c0, + this->c1 - other.c1, + this->c2 - other.c2); +} + +template& modulus> +Fp3_model operator*(const Fp_model &lhs, const Fp3_model &rhs) +{ + return Fp3_model(lhs*rhs.c0, + lhs*rhs.c1, + lhs*rhs.c2); +} + +template& modulus> +Fp3_model Fp3_model::operator*(const Fp3_model &other) const +{ + /* Devegili OhEig Scott Dahab --- Multiplication and Squaring on Pairing-Friendly Fields.pdf; Section 4 (Karatsuba) */ + const my_Fp + &A = other.c0, &B = other.c1, &C = other.c2, + &a = this->c0, &b = this->c1, &c = this->c2; + const my_Fp aA = a*A; + const my_Fp bB = b*B; + const my_Fp cC = c*C; + + return Fp3_model(aA + non_residue*((b+c)*(B+C)-bB-cC), + (a+b)*(A+B)-aA-bB+non_residue*cC, + (a+c)*(A+C)-aA+bB-cC); +} + +template& modulus> +Fp3_model Fp3_model::operator-() const +{ + return Fp3_model(-this->c0, + -this->c1, + -this->c2); +} + +template& modulus> +Fp3_model Fp3_model::squared() const +{ + /* Devegili OhEig Scott Dahab --- Multiplication and Squaring on Pairing-Friendly Fields.pdf; Section 4 (CH-SQR2) */ + const my_Fp + &a = this->c0, &b = this->c1, &c = this->c2; + const my_Fp s0 = a.squared(); + const my_Fp ab = a*b; + const my_Fp s1 = ab + ab; + const my_Fp s2 = (a - b + c).squared(); + const my_Fp bc = b*c; + const my_Fp s3 = bc + bc; + const my_Fp s4 = c.squared(); + + return Fp3_model(s0 + non_residue * s3, + s1 + non_residue * s4, + s1 + s2 + s3 - s0 - s4); +} + +template& modulus> +Fp3_model Fp3_model::inverse() const +{ + const my_Fp + &a = this->c0, &b = this->c1, &c = this->c2; + + /* From "High-Speed Software Implementation of the Optimal Ate Pairing over Barreto-Naehrig Curves"; Algorithm 17 */ + const my_Fp t0 = a.squared(); + const my_Fp t1 = b.squared(); + const my_Fp t2 = c.squared(); + const my_Fp t3 = a*b; + const my_Fp t4 = a*c; + const my_Fp t5 = b*c; + const my_Fp c0 = t0 - non_residue * t5; + const my_Fp c1 = non_residue * t2 - t3; + const my_Fp c2 = t1 - t4; // typo in paper referenced above. should be "-" as per Scott, but is "*" + const my_Fp t6 = (a * c0 + non_residue * (c * c1 + b * c2)).inverse(); + return Fp3_model(t6 * c0, t6 * c1, t6 * c2); +} + +template& modulus> +Fp3_model Fp3_model::Frobenius_map(unsigned long power) const +{ + return Fp3_model(c0, + Frobenius_coeffs_c1[power % 3] * c1, + Frobenius_coeffs_c2[power % 3] * c2); +} + +template& modulus> +Fp3_model Fp3_model::sqrt() const +{ + Fp3_model one = Fp3_model::one(); + + size_t v = Fp3_model::s; + Fp3_model z = Fp3_model::nqr_to_t; + Fp3_model w = (*this)^Fp3_model::t_minus_1_over_2; + Fp3_model x = (*this) * w; + Fp3_model b = x * w; // b = (*this)^t + +#if DEBUG + // check if square with euler's criterion + Fp3_model check = b; + for (size_t i = 0; i < v-1; ++i) + { + check = check.squared(); + } + if (check != one) + { + assert(0); + } +#endif + + // compute square root with Tonelli--Shanks + // (does not terminate if not a square!) + + while (b != one) + { + size_t m = 0; + Fp3_model b2m = b; + while (b2m != one) + { + /* invariant: b2m = b^(2^m) after entering this loop */ + b2m = b2m.squared(); + m += 1; + } + + int j = v-m-1; + w = z; + while (j > 0) + { + w = w.squared(); + --j; + } // w = z^2^(v-m-1) + + z = w.squared(); + b = b * z; + x = x * w; + v = m; + } + + return x; +} + +template& modulus> +template +Fp3_model Fp3_model::operator^(const bigint &pow) const +{ + return power >(*this, pow); +} + +template& modulus> +std::ostream& operator<<(std::ostream &out, const Fp3_model &el) +{ + out << el.c0 << OUTPUT_SEPARATOR << el.c1 << OUTPUT_SEPARATOR << el.c2; + return out; +} + +template& modulus> +std::istream& operator>>(std::istream &in, Fp3_model &el) +{ + in >> el.c0 >> el.c1 >> el.c2; + return in; +} + +template& modulus> +std::ostream& operator<<(std::ostream& out, const std::vector > &v) +{ + out << v.size() << "\n"; + for (const Fp3_model& t : v) + { + out << t << OUTPUT_NEWLINE; + } + + return out; +} + +template& modulus> +std::istream& operator>>(std::istream& in, std::vector > &v) +{ + v.clear(); + + size_t s; + in >> s; + + char b; + in.read(&b, 1); + + v.reserve(s); + + for (size_t i = 0; i < s; ++i) + { + Fp3_model el; + in >> el; + v.emplace_back(el); + } + + return in; +} + +} // libsnark +#endif // FP3_TCC_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/algebra/fields/fp4.hpp b/privacy/zsl/zsl/snark/libsnark/src/algebra/fields/fp4.hpp new file mode 100644 index 0000000..7e37807 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/algebra/fields/fp4.hpp @@ -0,0 +1,104 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for the (extension) field Fp4. + + The field Fp4 equals Fp2[V]/(V^2-U) where Fp2 = Fp[U]/(U^2-non_residue) and non_residue is in Fp. + + ASSUMPTION: the modulus p is 1 mod 6. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef FP4_HPP_ +#define FP4_HPP_ + +#include "algebra/fields/fp.hpp" +#include "algebra/fields/fp2.hpp" + +namespace libsnark { + +template& modulus> +class Fp4_model; + +template& modulus> +std::ostream& operator<<(std::ostream &, const Fp4_model &); + +template& modulus> +std::istream& operator>>(std::istream &, Fp4_model &); + +template& modulus> +class Fp4_model { +public: + typedef Fp_model my_Fp; + typedef Fp2_model my_Fp2; + typedef my_Fp2 my_Fpe; + + static my_Fp non_residue; + static my_Fp Frobenius_coeffs_c1[4]; // non_residue^((modulus^i-1)/4) for i=0,1,2,3 + + my_Fp2 c0, c1; + Fp4_model() {}; + Fp4_model(const my_Fp2& c0, const my_Fp2& c1) : c0(c0), c1(c1) {}; + + void print() const { printf("c0/c1:\n"); c0.print(); c1.print(); } + void clear() { c0.clear(); c1.clear(); } + + static Fp4_model zero(); + static Fp4_model one(); + static Fp4_model random_element(); + + bool is_zero() const { return c0.is_zero() && c1.is_zero(); } + bool operator==(const Fp4_model &other) const; + bool operator!=(const Fp4_model &other) const; + + Fp4_model operator+(const Fp4_model &other) const; + Fp4_model operator-(const Fp4_model &other) const; + Fp4_model operator*(const Fp4_model &other) const; + Fp4_model mul_by_023(const Fp4_model &other) const; + Fp4_model operator-() const; + Fp4_model squared() const; + Fp4_model inverse() const; + Fp4_model Frobenius_map(unsigned long power) const; + Fp4_model unitary_inverse() const; + Fp4_model cyclotomic_squared() const; + + static my_Fp2 mul_by_non_residue(const my_Fp2 &elt); + + template + Fp4_model cyclotomic_exp(const bigint &exponent) const; + + static bigint base_field_char() { return modulus; } + static constexpr size_t extension_degree() { return 4; } + + friend std::ostream& operator<< (std::ostream &out, const Fp4_model &el); + friend std::istream& operator>> (std::istream &in, Fp4_model &el); +}; + +template& modulus> +Fp4_model operator*(const Fp_model &lhs, const Fp4_model &rhs); + +template& modulus> +Fp4_model operator*(const Fp2_model &lhs, const Fp4_model &rhs); + +template& modulus, mp_size_t m> +Fp4_model operator^(const Fp4_model &self, const bigint &exponent); + +template& modulus, mp_size_t m, const bigint& modulus_p> +Fp4_model operator^(const Fp4_model &self, const Fp_model &exponent); + +template& modulus> +Fp_model Fp4_model::non_residue; + +template& modulus> +Fp_model Fp4_model::Frobenius_coeffs_c1[4]; + + +} // libsnark + +#include "algebra/fields/fp4.tcc" + +#endif // FP4_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/algebra/fields/fp4.tcc b/privacy/zsl/zsl/snark/libsnark/src/algebra/fields/fp4.tcc new file mode 100644 index 0000000..ffdec96 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/algebra/fields/fp4.tcc @@ -0,0 +1,245 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for the (extension) field Fp4. + + See fp4.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef FP4_TCC_ +#define FP4_TCC_ + +#include "algebra/fields/field_utils.hpp" +#include "algebra/scalar_multiplication/wnaf.hpp" + +namespace libsnark { + +template& modulus> +Fp2_model Fp4_model::mul_by_non_residue(const Fp2_model &elt) +{ + return Fp2_model(non_residue * elt.c1, elt.c0); +} + +template& modulus> +Fp4_model Fp4_model::zero() +{ + return Fp4_model(my_Fp2::zero(), + my_Fp2::zero()); +} + +template& modulus> +Fp4_model Fp4_model::one() +{ + return Fp4_model(my_Fp2::one(), + my_Fp2::zero()); +} + +template& modulus> +Fp4_model Fp4_model::random_element() +{ + Fp4_model r; + r.c0 = my_Fp2::random_element(); + r.c1 = my_Fp2::random_element(); + + return r; +} + +template& modulus> +bool Fp4_model::operator==(const Fp4_model &other) const +{ + return (this->c0 == other.c0 && this->c1 == other.c1); +} + +template& modulus> +bool Fp4_model::operator!=(const Fp4_model &other) const +{ + return !(operator==(other)); +} + +template& modulus> +Fp4_model Fp4_model::operator+(const Fp4_model &other) const +{ + return Fp4_model(this->c0 + other.c0, + this->c1 + other.c1); +} + +template& modulus> +Fp4_model Fp4_model::operator-(const Fp4_model &other) const +{ + return Fp4_model(this->c0 - other.c0, + this->c1 - other.c1); +} + +template& modulus> +Fp4_model operator*(const Fp_model &lhs, const Fp4_model &rhs) +{ + return Fp4_model(lhs*rhs.c0, + lhs*rhs.c1); +} + +template& modulus> +Fp4_model operator*(const Fp2_model &lhs, const Fp4_model &rhs) +{ + return Fp4_model(lhs*rhs.c0, + lhs*rhs.c1); +} + +template& modulus> +Fp4_model Fp4_model::operator*(const Fp4_model &other) const +{ + /* Devegili OhEig Scott Dahab --- Multiplication and Squaring on Pairing-Friendly Fields.pdf; Section 3 (Karatsuba) */ + + const my_Fp2 &B = other.c1, &A = other.c0, + &b = this->c1, &a = this->c0; + const my_Fp2 aA = a*A; + const my_Fp2 bB = b*B; + + const my_Fp2 beta_bB = Fp4_model::mul_by_non_residue(bB); + return Fp4_model(aA + beta_bB, + (a+b)*(A+B) - aA - bB); +} + +template& modulus> +Fp4_model Fp4_model::mul_by_023(const Fp4_model &other) const +{ + /* Devegili OhEig Scott Dahab --- Multiplication and Squaring on Pairing-Friendly Fields.pdf; Section 3 (Karatsuba) */ + assert(other.c0.c1.is_zero()); + + const my_Fp2 &B = other.c1, &A = other.c0, + &b = this->c1, &a = this->c0; + const my_Fp2 aA = my_Fp2(a.c0 * A.c0, a.c1 * A.c0); + const my_Fp2 bB = b*B; + + const my_Fp2 beta_bB = Fp4_model::mul_by_non_residue(bB); + return Fp4_model(aA + beta_bB, + (a+b)*(A+B) - aA - bB); +} + +template& modulus> +Fp4_model Fp4_model::operator-() const +{ + return Fp4_model(-this->c0, + -this->c1); +} + +template& modulus> +Fp4_model Fp4_model::squared() const +{ + /* Devegili OhEig Scott Dahab --- Multiplication and Squaring on Pairing-Friendly Fields.pdf; Section 3 (Complex) */ + + const my_Fp2 &b = this->c1, &a = this->c0; + const my_Fp2 ab = a * b; + + return Fp4_model((a+b)*(a+Fp4_model::mul_by_non_residue(b))-ab-Fp4_model::mul_by_non_residue(ab), + ab + ab); +} + +template& modulus> +Fp4_model Fp4_model::inverse() const +{ + /* From "High-Speed Software Implementation of the Optimal Ate Pairing over Barreto-Naehrig Curves"; Algorithm 8 */ + const my_Fp2 &b = this->c1, &a = this->c0; + const my_Fp2 t1 = b.squared(); + const my_Fp2 t0 = a.squared() - Fp4_model::mul_by_non_residue(t1); + const my_Fp2 new_t1 = t0.inverse(); + + return Fp4_model(a * new_t1, - (b * new_t1)); +} + +template& modulus> +Fp4_model Fp4_model::Frobenius_map(unsigned long power) const +{ + return Fp4_model(c0.Frobenius_map(power), + Frobenius_coeffs_c1[power % 4] * c1.Frobenius_map(power)); +} + +template& modulus> +Fp4_model Fp4_model::unitary_inverse() const +{ + return Fp4_model(this->c0, + -this->c1); +} + +template& modulus> +Fp4_model Fp4_model::cyclotomic_squared() const +{ + const my_Fp2 A = this->c1.squared(); + const my_Fp2 B = this->c1 + this->c0; + const my_Fp2 C = B.squared() - A; + const my_Fp2 D = Fp4_model::mul_by_non_residue(A); // Fp2(A.c1 * non_residue, A.c0) + const my_Fp2 E = C - D; + const my_Fp2 F = D + D + my_Fp2::one(); + const my_Fp2 G = E - my_Fp2::one(); + + return Fp4_model(F, G); +} + +template& modulus> +template +Fp4_model Fp4_model::cyclotomic_exp(const bigint &exponent) const +{ + Fp4_model res = Fp4_model::one(); + Fp4_model this_inverse = this->unitary_inverse(); + + bool found_nonzero = false; + std::vector NAF = find_wnaf(1, exponent); + + for (long i = NAF.size() - 1; i >= 0; --i) + { + if (found_nonzero) + { + res = res.cyclotomic_squared(); + } + + if (NAF[i] != 0) + { + found_nonzero = true; + + if (NAF[i] > 0) + { + res = res * (*this); + } + else + { + res = res * this_inverse; + } + } + } + + return res; +} + +template& modulus, mp_size_t m> +Fp4_model operator^(const Fp4_model &self, const bigint &exponent) +{ + return power >(self, exponent); +} + +template& modulus, mp_size_t m, const bigint& modulus_p> +Fp4_model operator^(const Fp4_model &self, const Fp_model &exponent) +{ + return self^(exponent.as_bigint()); +} + +template& modulus> +std::ostream& operator<<(std::ostream &out, const Fp4_model &el) +{ + out << el.c0 << OUTPUT_SEPARATOR << el.c1; + return out; +} + +template& modulus> +std::istream& operator>>(std::istream &in, Fp4_model &el) +{ + in >> el.c0 >> el.c1; + return in; +} + +} // libsnark + +#endif // FP4_TCC_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/algebra/fields/fp6_2over3.hpp b/privacy/zsl/zsl/snark/libsnark/src/algebra/fields/fp6_2over3.hpp new file mode 100644 index 0000000..61412b7 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/algebra/fields/fp6_2over3.hpp @@ -0,0 +1,108 @@ +/** @file + ***************************************************************************** + Declaration of arithmetic in the finite field F[(p^3)^2] + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef FP6_2OVER3_HPP_ +#define FP6_2OVER3_HPP_ +#include "algebra/fields/fp.hpp" +#include "algebra/fields/fp2.hpp" +#include "algebra/fields/fp3.hpp" + +namespace libsnark { + +/** + * Arithmetic in the finite field F[(p^3)^2]. + * + * Let p := modulus. This interface provides arithmetic for the extension field + * Fp6 = Fp3[Y]/(Y^2-X) where Fp3 = Fp[X]/(X^3-non_residue) and non_residue is in Fp. + * + * ASSUMPTION: p = 1 (mod 6) + */ +template& modulus> +class Fp6_2over3_model; + +template& modulus> +std::ostream& operator<<(std::ostream &, const Fp6_2over3_model &); + +template& modulus> +std::istream& operator>>(std::istream &, Fp6_2over3_model &); + +template& modulus> +class Fp6_2over3_model { +public: + typedef Fp_model my_Fp; + typedef Fp2_model my_Fp2; + typedef Fp3_model my_Fp3; + typedef my_Fp3 my_Fpe; + + static my_Fp non_residue; + static my_Fp Frobenius_coeffs_c1[6]; // non_residue^((modulus^i-1)/6) for i=0,1,2,3,4,5 + + my_Fp3 c0, c1; + Fp6_2over3_model() {}; + Fp6_2over3_model(const my_Fp3& c0, const my_Fp3& c1) : c0(c0), c1(c1) {}; + + void print() const { printf("c0/c1:\n"); c0.print(); c1.print(); } + void clear() { c0.clear(); c1.clear(); } + + static Fp6_2over3_model zero(); + static Fp6_2over3_model one(); + static Fp6_2over3_model random_element(); + + bool is_zero() const { return c0.is_zero() && c1.is_zero(); } + bool operator==(const Fp6_2over3_model &other) const; + bool operator!=(const Fp6_2over3_model &other) const; + + Fp6_2over3_model operator+(const Fp6_2over3_model &other) const; + Fp6_2over3_model operator-(const Fp6_2over3_model &other) const; + Fp6_2over3_model operator*(const Fp6_2over3_model &other) const; + Fp6_2over3_model mul_by_2345(const Fp6_2over3_model &other) const; + Fp6_2over3_model operator-() const; + Fp6_2over3_model squared() const; + Fp6_2over3_model inverse() const; + Fp6_2over3_model Frobenius_map(unsigned long power) const; + Fp6_2over3_model unitary_inverse() const; + Fp6_2over3_model cyclotomic_squared() const; + + static my_Fp3 mul_by_non_residue(const my_Fp3 &elem); + + template + Fp6_2over3_model cyclotomic_exp(const bigint &exponent) const; + + static bigint base_field_char() { return modulus; } + static constexpr size_t extension_degree() { return 6; } + + friend std::ostream& operator<< (std::ostream &out, const Fp6_2over3_model &el); + friend std::istream& operator>> (std::istream &in, Fp6_2over3_model &el); +}; + +template& modulus> +std::ostream& operator<<(std::ostream& out, const std::vector > &v); + +template& modulus> +std::istream& operator>>(std::istream& in, std::vector > &v); + +template& modulus> +Fp6_2over3_model operator*(const Fp_model &lhs, const Fp6_2over3_model &rhs); + +template& modulus, mp_size_t m> +Fp6_2over3_model operator^(const Fp6_2over3_model &self, const bigint &exponent); + +template& modulus, mp_size_t m, const bigint& exp_modulus> +Fp6_2over3_model operator^(const Fp6_2over3_model &self, const Fp_model &exponent); + +template& modulus> +Fp_model Fp6_2over3_model::non_residue; + +template& modulus> +Fp_model Fp6_2over3_model::Frobenius_coeffs_c1[6]; + +} // libsnark +#include "algebra/fields/fp6_2over3.tcc" + +#endif // FP6_2OVER3_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/algebra/fields/fp6_2over3.tcc b/privacy/zsl/zsl/snark/libsnark/src/algebra/fields/fp6_2over3.tcc new file mode 100644 index 0000000..cc4e46d --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/algebra/fields/fp6_2over3.tcc @@ -0,0 +1,274 @@ +/** @file + ***************************************************************************** + Implementation of arithmetic in the finite field F[(p^3)^2]. + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef FP6_2OVER3_TCC_ +#define FP6_2OVER3_TCC_ +#include "algebra/fields/field_utils.hpp" +#include "algebra/scalar_multiplication/wnaf.hpp" + +namespace libsnark { + +template& modulus> +Fp3_model Fp6_2over3_model::mul_by_non_residue(const Fp3_model &elem) +{ + return Fp3_model(non_residue * elem.c2, elem.c0, elem.c1); +} + +template& modulus> +Fp6_2over3_model Fp6_2over3_model::zero() +{ + return Fp6_2over3_model(my_Fp3::zero(), + my_Fp3::zero()); +} + +template& modulus> +Fp6_2over3_model Fp6_2over3_model::one() +{ + return Fp6_2over3_model(my_Fp3::one(), + my_Fp3::zero()); +} + +template& modulus> +Fp6_2over3_model Fp6_2over3_model::random_element() +{ + Fp6_2over3_model r; + r.c0 = my_Fp3::random_element(); + r.c1 = my_Fp3::random_element(); + + return r; +} + +template& modulus> +bool Fp6_2over3_model::operator==(const Fp6_2over3_model &other) const +{ + return (this->c0 == other.c0 && this->c1 == other.c1); +} + +template& modulus> +bool Fp6_2over3_model::operator!=(const Fp6_2over3_model &other) const +{ + return !(operator==(other)); +} + +template& modulus> +Fp6_2over3_model Fp6_2over3_model::operator+(const Fp6_2over3_model &other) const +{ + return Fp6_2over3_model(this->c0 + other.c0, + this->c1 + other.c1); +} + +template& modulus> +Fp6_2over3_model Fp6_2over3_model::operator-(const Fp6_2over3_model &other) const +{ + return Fp6_2over3_model(this->c0 - other.c0, + this->c1 - other.c1); +} + +template& modulus> +Fp6_2over3_model operator*(const Fp_model &lhs, const Fp6_2over3_model &rhs) +{ + return Fp6_2over3_model(lhs*rhs.c0, + lhs*rhs.c1); +} + +template& modulus> +Fp6_2over3_model Fp6_2over3_model::operator*(const Fp6_2over3_model &other) const +{ + /* Devegili OhEig Scott Dahab --- Multiplication and Squaring on Pairing-Friendly Fields.pdf; Section 3 (Karatsuba) */ + + const my_Fp3 &B = other.c1, &A = other.c0, + &b = this->c1, &a = this->c0; + const my_Fp3 aA = a*A; + const my_Fp3 bB = b*B; + const my_Fp3 beta_bB = Fp6_2over3_model::mul_by_non_residue(bB); + + return Fp6_2over3_model(aA + beta_bB, + (a+b)*(A+B) - aA - bB); +} + +template& modulus> +Fp6_2over3_model Fp6_2over3_model::mul_by_2345(const Fp6_2over3_model &other) const +{ + /* Devegili OhEig Scott Dahab --- Multiplication and Squaring on Pairing-Friendly Fields.pdf; Section 3 (Karatsuba) */ + assert(other.c0.c0.is_zero()); + assert(other.c0.c1.is_zero()); + + const my_Fp3 &B = other.c1, &A = other.c0, + &b = this->c1, &a = this->c0; + const my_Fp3 aA = my_Fp3(a.c1 * A.c2 * non_residue, a.c2 * A.c2 * non_residue, a.c0 * A.c2); + const my_Fp3 bB = b*B; + const my_Fp3 beta_bB = Fp6_2over3_model::mul_by_non_residue(bB); + + return Fp6_2over3_model(aA + beta_bB, + (a+b)*(A+B) - aA - bB); +} + +template& modulus> +Fp6_2over3_model Fp6_2over3_model::operator-() const +{ + return Fp6_2over3_model(-this->c0, + -this->c1); +} + +template& modulus> +Fp6_2over3_model Fp6_2over3_model::squared() const +{ + /* Devegili OhEig Scott Dahab --- Multiplication and Squaring on Pairing-Friendly Fields.pdf; Section 3 (Complex) */ + const my_Fp3 &b = this->c1, &a = this->c0; + const my_Fp3 ab = a * b; + + return Fp6_2over3_model((a+b)*(a+Fp6_2over3_model::mul_by_non_residue(b))-ab-Fp6_2over3_model::mul_by_non_residue(ab), + ab + ab); +} + +template& modulus> +Fp6_2over3_model Fp6_2over3_model::inverse() const +{ + /* From "High-Speed Software Implementation of the Optimal Ate Pairing over Barreto-Naehrig Curves"; Algorithm 8 */ + + const my_Fp3 &b = this->c1, &a = this->c0; + const my_Fp3 t1 = b.squared(); + const my_Fp3 t0 = a.squared() - Fp6_2over3_model::mul_by_non_residue(t1); + const my_Fp3 new_t1 = t0.inverse(); + + return Fp6_2over3_model(a * new_t1, + - (b * new_t1)); +} + +template& modulus> +Fp6_2over3_model Fp6_2over3_model::Frobenius_map(unsigned long power) const +{ + return Fp6_2over3_model(c0.Frobenius_map(power), + Frobenius_coeffs_c1[power % 6] * c1.Frobenius_map(power)); +} + +template& modulus> +Fp6_2over3_model Fp6_2over3_model::unitary_inverse() const +{ + return Fp6_2over3_model(this->c0, + -this->c1); +} + +template& modulus> +Fp6_2over3_model Fp6_2over3_model::cyclotomic_squared() const +{ + my_Fp2 a = my_Fp2(c0.c0, c1.c1); + //my_Fp a_a = c0.c0; // a = Fp2([c0[0],c1[1]]) + //my_Fp a_b = c1.c1; + + my_Fp2 b = my_Fp2(c1.c0, c0.c2); + //my_Fp b_a = c1.c0; // b = Fp2([c1[0],c0[2]]) + //my_Fp b_b = c0.c2; + + my_Fp2 c = my_Fp2(c0.c1, c1.c2); + //my_Fp c_a = c0.c1; // c = Fp2([c0[1],c1[2]]) + //my_Fp c_b = c1.c2; + + my_Fp2 asq = a.squared(); + my_Fp2 bsq = b.squared(); + my_Fp2 csq = c.squared(); + + // A = vector(3*a^2 - 2*Fp2([vector(a)[0],-vector(a)[1]])) + //my_Fp A_a = my_Fp(3l) * asq_a - my_Fp(2l) * a_a; + my_Fp A_a = asq.c0 - a.c0; + A_a = A_a + A_a + asq.c0; + //my_Fp A_b = my_Fp(3l) * asq_b + my_Fp(2l) * a_b; + my_Fp A_b = asq.c1 + a.c1; + A_b = A_b + A_b + asq.c1; + + // B = vector(3*Fp2([non_residue*c2[1],c2[0]]) + 2*Fp2([vector(b)[0],-vector(b)[1]])) + //my_Fp B_a = my_Fp(3l) * my_Fp3::non_residue * csq_b + my_Fp(2l) * b_a; + my_Fp B_tmp = my_Fp3::non_residue * csq.c1; + my_Fp B_a = B_tmp + b.c0; + B_a = B_a + B_a + B_tmp; + + //my_Fp B_b = my_Fp(3l) * csq_a - my_Fp(2l) * b_b; + my_Fp B_b = csq.c0 - b.c1; + B_b = B_b + B_b + csq.c0; + + // C = vector(3*b^2 - 2*Fp2([vector(c)[0],-vector(c)[1]])) + //my_Fp C_a = my_Fp(3l) * bsq_a - my_Fp(2l) * c_a; + my_Fp C_a = bsq.c0 - c.c0; + C_a = C_a + C_a + bsq.c0; + // my_Fp C_b = my_Fp(3l) * bsq_b + my_Fp(2l) * c_b; + my_Fp C_b = bsq.c1 + c.c1; + C_b = C_b + C_b + bsq.c1; + + // e0 = Fp3([A[0],C[0],B[1]]) + // e1 = Fp3([B[0],A[1],C[1]]) + // fin = Fp6e([e0,e1]) + // return fin + + return Fp6_2over3_model(my_Fp3(A_a, C_a, B_b), + my_Fp3(B_a, A_b, C_b)); +} + +template& modulus> +template +Fp6_2over3_model Fp6_2over3_model::cyclotomic_exp(const bigint &exponent) const +{ + Fp6_2over3_model res = Fp6_2over3_model::one(); + Fp6_2over3_model this_inverse = this->unitary_inverse(); + + bool found_nonzero = false; + std::vector NAF = find_wnaf(1, exponent); + + for (long i = NAF.size() - 1; i >= 0; --i) + { + if (found_nonzero) + { + res = res.cyclotomic_squared(); + } + + if (NAF[i] != 0) + { + found_nonzero = true; + + if (NAF[i] > 0) + { + res = res * (*this); + } + else + { + res = res * this_inverse; + } + } + } + + return res; +} + +template& modulus> +std::ostream& operator<<(std::ostream &out, const Fp6_2over3_model &el) +{ + out << el.c0 << OUTPUT_SEPARATOR << el.c1; + return out; +} + +template& modulus> +std::istream& operator>>(std::istream &in, Fp6_2over3_model &el) +{ + in >> el.c0 >> el.c1; + return in; +} + +template& modulus, mp_size_t m> +Fp6_2over3_model operator^(const Fp6_2over3_model &self, const bigint &exponent) +{ + return power, m>(self, exponent); +} + +template& modulus, mp_size_t m, const bigint& exp_modulus> +Fp6_2over3_model operator^(const Fp6_2over3_model &self, const Fp_model &exponent) +{ + return self^(exponent.as_bigint()); +} + +} // libsnark +#endif // FP6_2OVER3_TCC_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/algebra/fields/fp6_3over2.hpp b/privacy/zsl/zsl/snark/libsnark/src/algebra/fields/fp6_3over2.hpp new file mode 100644 index 0000000..335d61c --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/algebra/fields/fp6_3over2.hpp @@ -0,0 +1,104 @@ +/** @file + ***************************************************************************** + Declaration of arithmetic in the finite field F[(p^2)^3] + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef FP6_3OVER2_HPP_ +#define FP6_3OVER2_HPP_ +#include "algebra/fields/fp.hpp" +#include "algebra/fields/fp2.hpp" +#include + +namespace libsnark { + +template& modulus> +class Fp6_3over2_model; + +template& modulus> +std::ostream& operator<<(std::ostream &, const Fp6_3over2_model &); + +template& modulus> +std::istream& operator>>(std::istream &, Fp6_3over2_model &); + +/** + * Arithmetic in the finite field F[(p^2)^3]. + * + * Let p := modulus. This interface provides arithmetic for the extension field + * Fp6 = Fp2[V]/(V^3-non_residue) where non_residue is in Fp. + * + * ASSUMPTION: p = 1 (mod 6) + */ +template& modulus> +class Fp6_3over2_model { +public: + typedef Fp_model my_Fp; + typedef Fp2_model my_Fp2; + + static my_Fp2 non_residue; + static my_Fp2 Frobenius_coeffs_c1[6]; // non_residue^((modulus^i-1)/3) for i=0,1,2,3,4,5 + static my_Fp2 Frobenius_coeffs_c2[6]; // non_residue^((2*modulus^i-2)/3) for i=0,1,2,3,4,5 + + my_Fp2 c0, c1, c2; + Fp6_3over2_model() {}; + Fp6_3over2_model(const my_Fp2& c0, const my_Fp2& c1, const my_Fp2& c2) : c0(c0), c1(c1), c2(c2) {}; + + void clear() { c0.clear(); c1.clear(); c2.clear(); } + void print() const { printf("c0/c1/c2:\n"); c0.print(); c1.print(); c2.print(); } + + static Fp6_3over2_model zero(); + static Fp6_3over2_model one(); + static Fp6_3over2_model random_element(); + + bool is_zero() const { return c0.is_zero() && c1.is_zero() && c2.is_zero(); } + bool operator==(const Fp6_3over2_model &other) const; + bool operator!=(const Fp6_3over2_model &other) const; + + Fp6_3over2_model operator+(const Fp6_3over2_model &other) const; + Fp6_3over2_model operator-(const Fp6_3over2_model &other) const; + Fp6_3over2_model operator*(const Fp6_3over2_model &other) const; + Fp6_3over2_model operator-() const; + Fp6_3over2_model squared() const; + Fp6_3over2_model inverse() const; + Fp6_3over2_model Frobenius_map(unsigned long power) const; + + static my_Fp2 mul_by_non_residue(const my_Fp2 &elt); + + template + Fp6_3over2_model operator^(const bigint &other) const; + + static bigint base_field_char() { return modulus; } + static size_t extension_degree() { return 6; } + + friend std::ostream& operator<< (std::ostream &out, const Fp6_3over2_model &el); + friend std::istream& operator>> (std::istream &in, Fp6_3over2_model &el); +}; + +template& modulus> +std::ostream& operator<<(std::ostream& out, const std::vector > &v); + +template& modulus> +std::istream& operator>>(std::istream& in, std::vector > &v); + +template& modulus> +Fp6_3over2_model operator*(const Fp_model &lhs, const Fp6_3over2_model &rhs); + +template& modulus> +Fp6_3over2_model operator*(const Fp2_model &lhs, const Fp6_3over2_model &rhs); + +template& modulus> +Fp2_model Fp6_3over2_model::non_residue; + +template& modulus> +Fp2_model Fp6_3over2_model::Frobenius_coeffs_c1[6]; + +template& modulus> +Fp2_model Fp6_3over2_model::Frobenius_coeffs_c2[6]; + +} // libsnark +#include "algebra/fields/fp6_3over2.tcc" + +#endif // FP6_3OVER2_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/algebra/fields/fp6_3over2.tcc b/privacy/zsl/zsl/snark/libsnark/src/algebra/fields/fp6_3over2.tcc new file mode 100644 index 0000000..f4fffde --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/algebra/fields/fp6_3over2.tcc @@ -0,0 +1,216 @@ +/** @file + ***************************************************************************** + Implementation of arithmetic in the finite field F[(p^2)^3]. + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef FP6_3OVER2_TCC_ +#define FP6_3OVER2_TCC_ +#include "algebra/fields/field_utils.hpp" + +namespace libsnark { + +template& modulus> +Fp2_model Fp6_3over2_model::mul_by_non_residue(const Fp2_model &elt) +{ + return Fp2_model(non_residue * elt); +} + +template& modulus> +Fp6_3over2_model Fp6_3over2_model::zero() +{ + return Fp6_3over2_model(my_Fp2::zero(), my_Fp2::zero(), my_Fp2::zero()); +} + +template& modulus> +Fp6_3over2_model Fp6_3over2_model::one() +{ + return Fp6_3over2_model(my_Fp2::one(), my_Fp2::zero(), my_Fp2::zero()); +} + +template& modulus> +Fp6_3over2_model Fp6_3over2_model::random_element() +{ + Fp6_3over2_model r; + r.c0 = my_Fp2::random_element(); + r.c1 = my_Fp2::random_element(); + r.c2 = my_Fp2::random_element(); + + return r; +} + +template& modulus> +bool Fp6_3over2_model::operator==(const Fp6_3over2_model &other) const +{ + return (this->c0 == other.c0 && this->c1 == other.c1 && this->c2 == other.c2); +} + +template& modulus> +bool Fp6_3over2_model::operator!=(const Fp6_3over2_model &other) const +{ + return !(operator==(other)); +} + +template& modulus> +Fp6_3over2_model Fp6_3over2_model::operator+(const Fp6_3over2_model &other) const +{ + return Fp6_3over2_model(this->c0 + other.c0, + this->c1 + other.c1, + this->c2 + other.c2); +} + +template& modulus> +Fp6_3over2_model Fp6_3over2_model::operator-(const Fp6_3over2_model &other) const +{ + return Fp6_3over2_model(this->c0 - other.c0, + this->c1 - other.c1, + this->c2 - other.c2); +} + +template& modulus> +Fp6_3over2_model operator*(const Fp_model &lhs, const Fp6_3over2_model &rhs) +{ + return Fp6_3over2_model(lhs*rhs.c0, + lhs*rhs.c1, + lhs*rhs.c2); +} + +template& modulus> +Fp6_3over2_model operator*(const Fp2_model &lhs, const Fp6_3over2_model &rhs) +{ + return Fp6_3over2_model(lhs*rhs.c0, + lhs*rhs.c1, + lhs*rhs.c2); +} + +template& modulus> +Fp6_3over2_model Fp6_3over2_model::operator*(const Fp6_3over2_model &other) const +{ + /* Devegili OhEig Scott Dahab --- Multiplication and Squaring on Pairing-Friendly Fields.pdf; Section 4 (Karatsuba) */ + + const my_Fp2 &A = other.c0, &B = other.c1, &C = other.c2, + &a = this->c0, &b = this->c1, &c = this->c2; + const my_Fp2 aA = a*A; + const my_Fp2 bB = b*B; + const my_Fp2 cC = c*C; + + return Fp6_3over2_model(aA + Fp6_3over2_model::mul_by_non_residue((b+c)*(B+C)-bB-cC), + (a+b)*(A+B)-aA-bB+Fp6_3over2_model::mul_by_non_residue(cC), + (a+c)*(A+C)-aA+bB-cC); +} + +template& modulus> +Fp6_3over2_model Fp6_3over2_model::operator-() const +{ + return Fp6_3over2_model(-this->c0, + -this->c1, + -this->c2); +} + +template& modulus> +Fp6_3over2_model Fp6_3over2_model::squared() const +{ + /* Devegili OhEig Scott Dahab --- Multiplication and Squaring on Pairing-Friendly Fields.pdf; Section 4 (CH-SQR2) */ + + const my_Fp2 &a = this->c0, &b = this->c1, &c = this->c2; + const my_Fp2 s0 = a.squared(); + const my_Fp2 ab = a*b; + const my_Fp2 s1 = ab + ab; + const my_Fp2 s2 = (a - b + c).squared(); + const my_Fp2 bc = b*c; + const my_Fp2 s3 = bc + bc; + const my_Fp2 s4 = c.squared(); + + return Fp6_3over2_model(s0 + Fp6_3over2_model::mul_by_non_residue(s3), + s1 + Fp6_3over2_model::mul_by_non_residue(s4), + s1 + s2 + s3 - s0 - s4); +} + +template& modulus> +Fp6_3over2_model Fp6_3over2_model::inverse() const +{ + /* From "High-Speed Software Implementation of the Optimal Ate Pairing over Barreto-Naehrig Curves"; Algorithm 17 */ + + const my_Fp2 &a = this->c0, &b = this->c1, &c = this->c2; + const my_Fp2 t0 = a.squared(); + const my_Fp2 t1 = b.squared(); + const my_Fp2 t2 = c.squared(); + const my_Fp2 t3 = a*b; + const my_Fp2 t4 = a*c; + const my_Fp2 t5 = b*c; + const my_Fp2 c0 = t0 - Fp6_3over2_model::mul_by_non_residue(t5); + const my_Fp2 c1 = Fp6_3over2_model::mul_by_non_residue(t2) - t3; + const my_Fp2 c2 = t1 - t4; // typo in paper referenced above. should be "-" as per Scott, but is "*" + const my_Fp2 t6 = (a * c0 + Fp6_3over2_model::mul_by_non_residue((c * c1 + b * c2))).inverse(); + return Fp6_3over2_model(t6 * c0, t6 * c1, t6 * c2); +} + +template& modulus> +Fp6_3over2_model Fp6_3over2_model::Frobenius_map(unsigned long power) const +{ + return Fp6_3over2_model(c0.Frobenius_map(power), + Frobenius_coeffs_c1[power % 6] * c1.Frobenius_map(power), + Frobenius_coeffs_c2[power % 6] * c2.Frobenius_map(power)); +} + +template& modulus> +template +Fp6_3over2_model Fp6_3over2_model::operator^(const bigint &pow) const +{ + return power, m>(*this, pow); +} + +template& modulus> +std::ostream& operator<<(std::ostream &out, const Fp6_3over2_model &el) +{ + out << el.c0 << OUTPUT_SEPARATOR << el.c1 << OUTPUT_SEPARATOR << el.c2; + return out; +} + +template& modulus> +std::istream& operator>>(std::istream &in, Fp6_3over2_model &el) +{ + in >> el.c0 >> el.c1 >> el.c2; + return in; +} + +template& modulus> +std::ostream& operator<<(std::ostream& out, const std::vector > &v) +{ + out << v.size() << "\n"; + for (const Fp6_3over2_model& t : v) + { + out << t << OUTPUT_NEWLINE; + } + + return out; +} + +template& modulus> +std::istream& operator>>(std::istream& in, std::vector > &v) +{ + v.clear(); + + size_t s; + in >> s; + + char b; + in.read(&b, 1); + + v.reserve(s); + + for (size_t i = 0; i < s; ++i) + { + Fp6_3over2_model el; + in >> el; + v.emplace_back(el); + } + + return in; +} + +} // libsnark +#endif // FP6_3_OVER_2_TCC_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/algebra/fields/fp_aux.tcc b/privacy/zsl/zsl/snark/libsnark/src/algebra/fields/fp_aux.tcc new file mode 100644 index 0000000..7f8a3ea --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/algebra/fields/fp_aux.tcc @@ -0,0 +1,389 @@ +/** @file + ***************************************************************************** + Assembly code snippets for F[p] finite field arithmetic, used by fp.tcc . + Specific to x86-64, and used only if USE_ASM is defined. + On other architectures or without USE_ASM, fp.tcc uses a portable + C++ implementation instead. + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef FP_AUX_TCC_ +#define FP_AUX_TCC_ + +namespace libsnark { + +#define STR_HELPER(x) #x +#define STR(x) STR_HELPER(x) + +/* addq is faster than adcq, even if preceded by clc */ +#define ADD_FIRSTADD \ + "movq (%[B]), %%rax \n\t" \ + "addq %%rax, (%[A]) \n\t" + +#define ADD_NEXTADD(ofs) \ + "movq " STR(ofs) "(%[B]), %%rax \n\t" \ + "adcq %%rax, " STR(ofs) "(%[A]) \n\t" + +#define ADD_CMP(ofs) \ + "movq " STR(ofs) "(%[mod]), %%rax \n\t" \ + "cmpq %%rax, " STR(ofs) "(%[A]) \n\t" \ + "jb done%= \n\t" \ + "ja subtract%= \n\t" + +#define ADD_FIRSTSUB \ + "movq (%[mod]), %%rax \n\t" \ + "subq %%rax, (%[A]) \n\t" + +#define ADD_FIRSTSUB \ + "movq (%[mod]), %%rax \n\t" \ + "subq %%rax, (%[A]) \n\t" + +#define ADD_NEXTSUB(ofs) \ + "movq " STR(ofs) "(%[mod]), %%rax \n\t" \ + "sbbq %%rax, " STR(ofs) "(%[A]) \n\t" + +#define SUB_FIRSTSUB \ + "movq (%[B]), %%rax\n\t" \ + "subq %%rax, (%[A])\n\t" + +#define SUB_NEXTSUB(ofs) \ + "movq " STR(ofs) "(%[B]), %%rax\n\t" \ + "sbbq %%rax, " STR(ofs) "(%[A])\n\t" + +#define SUB_FIRSTADD \ + "movq (%[mod]), %%rax\n\t" \ + "addq %%rax, (%[A])\n\t" + +#define SUB_NEXTADD(ofs) \ + "movq " STR(ofs) "(%[mod]), %%rax\n\t" \ + "adcq %%rax, " STR(ofs) "(%[A])\n\t" + +#define MONT_CMP(ofs) \ + "movq " STR(ofs) "(%[M]), %%rax \n\t" \ + "cmpq %%rax, " STR(ofs) "(%[tmp]) \n\t" \ + "jb done%= \n\t" \ + "ja subtract%= \n\t" + +#define MONT_FIRSTSUB \ + "movq (%[M]), %%rax \n\t" \ + "subq %%rax, (%[tmp]) \n\t" + +#define MONT_NEXTSUB(ofs) \ + "movq " STR(ofs) "(%[M]), %%rax \n\t" \ + "sbbq %%rax, " STR(ofs) "(%[tmp]) \n\t" + +/* + The x86-64 Montgomery multiplication here is similar + to Algorithm 2 (CIOS method) in http://eprint.iacr.org/2012/140.pdf + and the PowerPC pseudocode of gmp-ecm library (c) Paul Zimmermann and Alexander Kruppa + (see comments on top of powerpc64/mulredc.m4). +*/ + +#define MONT_PRECOMPUTE \ + "xorq %[cy], %[cy] \n\t" \ + "movq 0(%[A]), %%rax \n\t" \ + "mulq 0(%[B]) \n\t" \ + "movq %%rax, %[T0] \n\t" \ + "movq %%rdx, %[T1] # T1:T0 <- A[0] * B[0] \n\t" \ + "mulq %[inv] \n\t" \ + "movq %%rax, %[u] # u <- T0 * inv \n\t" \ + "mulq 0(%[M]) \n\t" \ + "addq %[T0], %%rax \n\t" \ + "adcq %%rdx, %[T1] \n\t" \ + "adcq $0, %[cy] # cy:T1 <- (M[0]*u + T1 * b + T0) / b\n\t" + +#define MONT_FIRSTITER(j) \ + "xorq %[T0], %[T0] \n\t" \ + "movq 0(%[A]), %%rax \n\t" \ + "mulq " STR((j*8)) "(%[B]) \n\t" \ + "addq %[T1], %%rax \n\t" \ + "movq %%rax, " STR(((j-1)*8)) "(%[tmp]) \n\t" \ + "adcq $0, %%rdx \n\t" \ + "movq %%rdx, %[T1] # now T1:tmp[j-1] <-- X[0] * Y[j] + T1\n\t" \ + "movq " STR((j*8)) "(%[M]), %%rax \n\t" \ + "mulq %[u] \n\t" \ + "addq %%rax, " STR(((j-1)*8)) "(%[tmp]) \n\t" \ + "adcq %[cy], %%rdx \n\t" \ + "adcq $0, %[T0] \n\t" \ + "xorq %[cy], %[cy] \n\t" \ + "addq %%rdx, %[T1] \n\t" \ + "adcq %[T0], %[cy] # cy:T1:tmp[j-1] <---- (X[0] * Y[j] + T1) + (M[j] * u + cy * b) \n\t" + +#define MONT_ITERFIRST(i) \ + "xorq %[cy], %[cy] \n\t" \ + "movq " STR((i*8)) "(%[A]), %%rax \n\t" \ + "mulq 0(%[B]) \n\t" \ + "addq 0(%[tmp]), %%rax \n\t" \ + "adcq 8(%[tmp]), %%rdx \n\t" \ + "adcq $0, %[cy] \n\t" \ + "movq %%rax, %[T0] \n\t" \ + "movq %%rdx, %[T1] # cy:T1:T0 <- A[i] * B[0] + tmp[1] * b + tmp[0]\n\t" \ + "mulq %[inv] \n\t" \ + "movq %%rax, %[u] # u <- T0 * inv\n\t" \ + "mulq 0(%[M]) \n\t" \ + "addq %[T0], %%rax \n\t" \ + "adcq %%rdx, %[T1] \n\t" \ + "adcq $0, %[cy] # cy:T1 <- (M[0]*u + cy * b * b + T1 * b + T0) / b\n\t" + +#define MONT_ITERITER(i, j) \ + "xorq %[T0], %[T0] \n\t" \ + "movq " STR((i*8)) "(%[A]), %%rax \n\t" \ + "mulq " STR((j*8)) "(%[B]) \n\t" \ + "addq %[T1], %%rax \n\t" \ + "movq %%rax, " STR(((j-1)*8)) "(%[tmp]) \n\t" \ + "adcq $0, %%rdx \n\t" \ + "movq %%rdx, %[T1] # now T1:tmp[j-1] <-- X[i] * Y[j] + T1 \n\t" \ + "movq " STR((j*8)) "(%[M]), %%rax \n\t" \ + "mulq %[u] \n\t" \ + "addq %%rax, " STR(((j-1)*8)) "(%[tmp]) \n\t" \ + "adcq %[cy], %%rdx \n\t" \ + "adcq $0, %[T0] \n\t" \ + "xorq %[cy], %[cy] \n\t" \ + "addq %%rdx, %[T1] \n\t" \ + "adcq %[T0], %[cy] # cy:T1:tmp[j-1] <-- (X[i] * Y[j] + T1) + M[j] * u + cy * b \n\t" \ + "addq " STR(((j+1)*8)) "(%[tmp]), %[T1] \n\t" \ + "adcq $0, %[cy] # cy:T1:tmp[j-1] <-- (X[i] * Y[j] + T1) + M[j] * u + (tmp[j+1] + cy) * b \n\t" + +#define MONT_FINALIZE(j) \ + "movq %[T1], " STR((j*8)) "(%[tmp]) \n\t" \ + "movq %[cy], " STR(((j+1)*8)) "(%[tmp]) \n\t" + +/* + Comba multiplication and squaring routines are based on the + public-domain tomsfastmath library by Tom St Denis + + + + Compared to the above, we save 5-20% of cycles by using careful register + renaming to implement Comba forward operation. + */ + +#define COMBA_3_BY_3_MUL(c0_, c1_, c2_, res_, A_, B_) \ + asm volatile ( \ + "movq 0(%[A]), %%rax \n\t" \ + "mulq 0(%[B]) \n\t" \ + "movq %%rax, 0(%[res]) \n\t" \ + "movq %%rdx, %[c0] \n\t" \ + \ + "xorq %[c1], %[c1] \n\t" \ + "movq 0(%[A]), %%rax \n\t" \ + "mulq 8(%[B]) \n\t" \ + "addq %%rax, %[c0] \n\t" \ + "adcq %%rdx, %[c1] \n\t" \ + \ + "xorq %[c2], %[c2] \n\t" \ + "movq 8(%[A]), %%rax \n\t" \ + "mulq 0(%[B]) \n\t" \ + "addq %%rax, %[c0] \n\t" \ + "movq %[c0], 8(%[res]) \n\t" \ + "adcq %%rdx, %[c1] \n\t" \ + "adcq $0, %[c2] \n\t" \ + \ + "// register renaming (c1, c2, c0)\n\t" \ + "xorq %[c0], %[c0] \n\t" \ + "movq 0(%[A]), %%rax \n\t" \ + "mulq 16(%[B]) \n\t" \ + "addq %%rax, %[c1] \n\t" \ + "adcq %%rdx, %[c2] \n\t" \ + "adcq $0, %[c0] \n\t" \ + \ + "movq 8(%[A]), %%rax \n\t" \ + "mulq 8(%[B]) \n\t" \ + "addq %%rax, %[c1] \n\t" \ + "adcq %%rdx, %[c2] \n\t" \ + "adcq $0, %[c0] \n\t" \ + \ + "movq 16(%[A]), %%rax \n\t" \ + "mulq 0(%[B]) \n\t" \ + "addq %%rax, %[c1] \n\t" \ + "movq %[c1], 16(%[res]) \n\t" \ + "adcq %%rdx, %[c2] \n\t" \ + "adcq $0, %[c0] \n\t" \ + \ + "// register renaming (c2, c0, c1)\n\t" \ + "xorq %[c1], %[c1] \n\t" \ + "movq 8(%[A]), %%rax \n\t" \ + "mulq 16(%[B]) \n\t" \ + "addq %%rax, %[c2] \n\t" \ + "adcq %%rdx, %[c0] \n\t" \ + "adcq $0, %[c1] \n\t" \ + \ + "movq 16(%[A]), %%rax \n\t" \ + "mulq 8(%[B]) \n\t" \ + "addq %%rax, %[c2] \n\t" \ + "movq %[c2], 24(%[res]) \n\t" \ + "adcq %%rdx, %[c0] \n\t" \ + "adcq $0, %[c1] \n\t" \ + \ + "// register renaming (c0, c1, c2)\n\t" \ + "xorq %[c2], %[c2] \n\t" \ + "movq 16(%[A]), %%rax \n\t" \ + "mulq 16(%[B]) \n\t" \ + "addq %%rax, %[c0] \n\t" \ + "movq %[c0], 32(%[res]) \n\t" \ + "adcq %%rdx, %[c1] \n\t" \ + "movq %[c1], 40(%[res]) \n\t" \ + : [c0] "=&r" (c0_), [c1] "=&r" (c1_), [c2] "=&r" (c2_) \ + : [res] "r" (res_), [A] "r" (A_), [B] "r" (B_) \ + : "%rax", "%rdx", "cc", "memory") + +#define COMBA_3_BY_3_SQR(c0_, c1_, c2_, res_, A_) \ + asm volatile ( \ + "xorq %[c1], %[c1] \n\t" \ + "xorq %[c2], %[c2] \n\t" \ + "movq 0(%[A]), %%rax \n\t" \ + "mulq %%rax \n\t" \ + "movq %%rax, 0(%[res]) \n\t" \ + "movq %%rdx, %[c0] \n\t" \ + \ + "movq 0(%[A]), %%rax \n\t" \ + "mulq 8(%[A]) \n\t" \ + "addq %%rax, %[c0] \n\t" \ + "adcq %%rdx, %[c1] \n\t" \ + "addq %%rax, %[c0] \n\t" \ + "movq %[c0], 8(%[res]) \n\t" \ + "adcq %%rdx, %[c1] \n\t" \ + "adcq $0, %[c2] \n\t" \ + \ + "// register renaming (c1, c2, c0)\n\t" \ + "movq 0(%[A]), %%rax \n\t" \ + "xorq %[c0], %[c0] \n\t" \ + "mulq 16(%[A]) \n\t" \ + "addq %%rax, %[c1] \n\t" \ + "adcq %%rdx, %[c2] \n\t" \ + "adcq $0, %[c0] \n\t" \ + "addq %%rax, %[c1] \n\t" \ + "adcq %%rdx, %[c2] \n\t" \ + "adcq $0, %[c0] \n\t" \ + \ + "movq 8(%[A]), %%rax \n\t" \ + "mulq %%rax \n\t" \ + "addq %%rax, %[c1] \n\t" \ + "movq %[c1], 16(%[res]) \n\t" \ + "adcq %%rdx, %[c2] \n\t" \ + "adcq $0, %[c0] \n\t" \ + \ + "// register renaming (c2, c0, c1)\n\t" \ + "movq 8(%[A]), %%rax \n\t" \ + "xorq %[c1], %[c1] \n\t" \ + "mulq 16(%[A]) \n\t" \ + "addq %%rax, %[c2] \n\t" \ + "adcq %%rdx, %[c0] \n\t" \ + "adcq $0, %[c1] \n\t" \ + "addq %%rax, %[c2] \n\t" \ + "movq %[c2], 24(%[res]) \n\t" \ + "adcq %%rdx, %[c0] \n\t" \ + "adcq $0, %[c1] \n\t" \ + \ + "// register renaming (c0, c1, c2)\n\t" \ + "movq 16(%[A]), %%rax \n\t" \ + "mulq %%rax \n\t" \ + "addq %%rax, %[c0] \n\t" \ + "movq %[c0], 32(%[res]) \n\t" \ + "adcq %%rdx, %[c1] \n\t" \ + "movq %[c1], 40(%[res]) \n\t" \ + \ + : [c0] "=&r" (c0_), [c1] "=&r" (c1_), [c2] "=&r" (c2_) \ + : [res] "r" (res_), [A] "r" (A_) \ + : "%rax", "%rdx", "cc", "memory") + +/* + The Montgomery reduction here is based on Algorithm 14.32 in + Handbook of Applied Cryptography + . + */ +#define REDUCE_6_LIMB_PRODUCT(k_, tmp1_, tmp2_, tmp3_, inv_, res_, mod_) \ + __asm__ volatile \ + ("///////////////////////////////////\n\t" \ + "movq 0(%[res]), %%rax \n\t" \ + "mulq %[modprime] \n\t" \ + "movq %%rax, %[k] \n\t" \ + \ + "movq (%[mod]), %%rax \n\t" \ + "mulq %[k] \n\t" \ + "movq %%rax, %[tmp1] \n\t" \ + "movq %%rdx, %[tmp2] \n\t" \ + \ + "xorq %[tmp3], %[tmp3] \n\t" \ + "movq 8(%[mod]), %%rax \n\t" \ + "mulq %[k] \n\t" \ + "addq %[tmp1], 0(%[res]) \n\t" \ + "adcq %%rax, %[tmp2] \n\t" \ + "adcq %%rdx, %[tmp3] \n\t" \ + \ + "xorq %[tmp1], %[tmp1] \n\t" \ + "movq 16(%[mod]), %%rax \n\t" \ + "mulq %[k] \n\t" \ + "addq %[tmp2], 8(%[res]) \n\t" \ + "adcq %%rax, %[tmp3] \n\t" \ + "adcq %%rdx, %[tmp1] \n\t" \ + \ + "addq %[tmp3], 16(%[res]) \n\t" \ + "adcq %[tmp1], 24(%[res]) \n\t" \ + "adcq $0, 32(%[res]) \n\t" \ + "adcq $0, 40(%[res]) \n\t" \ + \ + "///////////////////////////////////\n\t" \ + "movq 8(%[res]), %%rax \n\t" \ + "mulq %[modprime] \n\t" \ + "movq %%rax, %[k] \n\t" \ + \ + "movq (%[mod]), %%rax \n\t" \ + "mulq %[k] \n\t" \ + "movq %%rax, %[tmp1] \n\t" \ + "movq %%rdx, %[tmp2] \n\t" \ + \ + "xorq %[tmp3], %[tmp3] \n\t" \ + "movq 8(%[mod]), %%rax \n\t" \ + "mulq %[k] \n\t" \ + "addq %[tmp1], 8(%[res]) \n\t" \ + "adcq %%rax, %[tmp2] \n\t" \ + "adcq %%rdx, %[tmp3] \n\t" \ + \ + "xorq %[tmp1], %[tmp1] \n\t" \ + "movq 16(%[mod]), %%rax \n\t" \ + "mulq %[k] \n\t" \ + "addq %[tmp2], 16(%[res]) \n\t" \ + "adcq %%rax, %[tmp3] \n\t" \ + "adcq %%rdx, %[tmp1] \n\t" \ + \ + "addq %[tmp3], 24(%[res]) \n\t" \ + "adcq %[tmp1], 32(%[res]) \n\t" \ + "adcq $0, 40(%[res]) \n\t" \ + \ + "///////////////////////////////////\n\t" \ + "movq 16(%[res]), %%rax \n\t" \ + "mulq %[modprime] \n\t" \ + "movq %%rax, %[k] \n\t" \ + \ + "movq (%[mod]), %%rax \n\t" \ + "mulq %[k] \n\t" \ + "movq %%rax, %[tmp1] \n\t" \ + "movq %%rdx, %[tmp2] \n\t" \ + \ + "xorq %[tmp3], %[tmp3] \n\t" \ + "movq 8(%[mod]), %%rax \n\t" \ + "mulq %[k] \n\t" \ + "addq %[tmp1], 16(%[res]) \n\t" \ + "adcq %%rax, %[tmp2] \n\t" \ + "adcq %%rdx, %[tmp3] \n\t" \ + \ + "xorq %[tmp1], %[tmp1] \n\t" \ + "movq 16(%[mod]), %%rax \n\t" \ + "mulq %[k] \n\t" \ + "addq %[tmp2], 24(%[res]) \n\t" \ + "adcq %%rax, %[tmp3] \n\t" \ + "adcq %%rdx, %[tmp1] \n\t" \ + \ + "addq %[tmp3], 32(%[res]) \n\t" \ + "adcq %[tmp1], 40(%[res]) \n\t" \ + : [k] "=&r" (k_), [tmp1] "=&r" (tmp1_), [tmp2] "=&r" (tmp2_), [tmp3] "=&r" (tmp3_) \ + : [modprime] "r" (inv_), [res] "r" (res_), [mod] "r" (mod_) \ + : "%rax", "%rdx", "cc", "memory") + +} // libsnark +#endif // FP_AUX_TCC_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/algebra/fields/tests/test_fields.cpp b/privacy/zsl/zsl/snark/libsnark/src/algebra/fields/tests/test_fields.cpp new file mode 100644 index 0000000..a05f601 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/algebra/fields/tests/test_fields.cpp @@ -0,0 +1,245 @@ +/** + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ +#include "common/profiling.hpp" +#include "algebra/curves/edwards/edwards_pp.hpp" +#include "algebra/curves/mnt/mnt4/mnt4_pp.hpp" +#include "algebra/curves/mnt/mnt6/mnt6_pp.hpp" +#ifdef CURVE_BN128 +#include "algebra/curves/bn128/bn128_pp.hpp" +#endif +#include "algebra/curves/alt_bn128/alt_bn128_pp.hpp" +#include "algebra/fields/fp6_3over2.hpp" +#include "algebra/fields/fp12_2over3over2.hpp" + +using namespace libsnark; + +template +void test_field() +{ + bigint<1> rand1 = bigint<1>("76749407"); + bigint<1> rand2 = bigint<1>("44410867"); + bigint<1> randsum = bigint<1>("121160274"); + + FieldT zero = FieldT::zero(); + FieldT one = FieldT::one(); + FieldT a = FieldT::random_element(); + FieldT a_ser; + a_ser = reserialize(a); + assert(a_ser == a); + + FieldT b = FieldT::random_element(); + FieldT c = FieldT::random_element(); + FieldT d = FieldT::random_element(); + + assert(a != zero); + assert(a != one); + + assert(a * a == a.squared()); + assert((a + b).squared() == a.squared() + a*b + b*a + b.squared()); + assert((a + b)*(c + d) == a*c + a*d + b*c + b*d); + assert(a - b == a + (-b)); + assert(a - b == (-b) + a); + + assert((a ^ rand1) * (a ^ rand2) == (a^randsum)); + + assert(a * a.inverse() == one); + assert((a + b) * c.inverse() == a * c.inverse() + (b.inverse() * c).inverse()); + +} + +template +void test_sqrt() +{ + for (size_t i = 0; i < 100; ++i) + { + FieldT a = FieldT::random_element(); + FieldT asq = a.squared(); + assert(asq.sqrt() == a || asq.sqrt() == -a); + } +} + +template +void test_two_squarings() +{ + FieldT a = FieldT::random_element(); + assert(a.squared() == a * a); + assert(a.squared() == a.squared_complex()); + assert(a.squared() == a.squared_karatsuba()); +} + +template +void test_Frobenius() +{ + FieldT a = FieldT::random_element(); + assert(a.Frobenius_map(0) == a); + FieldT a_q = a ^ FieldT::base_field_char(); + for (size_t power = 1; power < 10; ++power) + { + const FieldT a_qi = a.Frobenius_map(power); + assert(a_qi == a_q); + + a_q = a_q ^ FieldT::base_field_char(); + } +} + +template +void test_unitary_inverse() +{ + assert(FieldT::extension_degree() % 2 == 0); + FieldT a = FieldT::random_element(); + FieldT aqcubed_minus1 = a.Frobenius_map(FieldT::extension_degree()/2) * a.inverse(); + assert(aqcubed_minus1.inverse() == aqcubed_minus1.unitary_inverse()); +} + +template +void test_cyclotomic_squaring(); + +template<> +void test_cyclotomic_squaring >() +{ + typedef Fqk FieldT; + assert(FieldT::extension_degree() % 2 == 0); + FieldT a = FieldT::random_element(); + FieldT a_unitary = a.Frobenius_map(FieldT::extension_degree()/2) * a.inverse(); + // beta = a^((q^(k/2)-1)*(q+1)) + FieldT beta = a_unitary.Frobenius_map(1) * a_unitary; + assert(beta.cyclotomic_squared() == beta.squared()); +} + +template<> +void test_cyclotomic_squaring >() +{ + typedef Fqk FieldT; + assert(FieldT::extension_degree() % 2 == 0); + FieldT a = FieldT::random_element(); + FieldT a_unitary = a.Frobenius_map(FieldT::extension_degree()/2) * a.inverse(); + // beta = a^(q^(k/2)-1) + FieldT beta = a_unitary; + assert(beta.cyclotomic_squared() == beta.squared()); +} + +template<> +void test_cyclotomic_squaring >() +{ + typedef Fqk FieldT; + assert(FieldT::extension_degree() % 2 == 0); + FieldT a = FieldT::random_element(); + FieldT a_unitary = a.Frobenius_map(FieldT::extension_degree()/2) * a.inverse(); + // beta = a^((q^(k/2)-1)*(q+1)) + FieldT beta = a_unitary.Frobenius_map(1) * a_unitary; + assert(beta.cyclotomic_squared() == beta.squared()); +} + +template +void test_all_fields() +{ + test_field >(); + test_field >(); + test_field >(); + test_field >(); + + test_sqrt >(); + test_sqrt >(); + test_sqrt >(); + + test_Frobenius >(); + test_Frobenius >(); + + test_unitary_inverse >(); +} + +template +void test_Fp4_tom_cook() +{ + typedef typename Fp4T::my_Fp FieldT; + for (size_t i = 0; i < 100; ++i) + { + const Fp4T a = Fp4T::random_element(); + const Fp4T b = Fp4T::random_element(); + const Fp4T correct_res = a * b; + + Fp4T res; + + const FieldT + &a0 = a.c0.c0, + &a1 = a.c1.c0, + &a2 = a.c0.c1, + &a3 = a.c1.c1; + + const FieldT + &b0 = b.c0.c0, + &b1 = b.c1.c0, + &b2 = b.c0.c1, + &b3 = b.c1.c1; + + FieldT + &c0 = res.c0.c0, + &c1 = res.c1.c0, + &c2 = res.c0.c1, + &c3 = res.c1.c1; + + const FieldT v0 = a0 * b0; + const FieldT v1 = (a0 + a1 + a2 + a3) * (b0 + b1 + b2 + b3); + const FieldT v2 = (a0 - a1 + a2 - a3) * (b0 - b1 + b2 - b3); + const FieldT v3 = (a0 + FieldT(2)*a1 + FieldT(4)*a2 + FieldT(8)*a3) * (b0 + FieldT(2)*b1 + FieldT(4)*b2 + FieldT(8)*b3); + const FieldT v4 = (a0 - FieldT(2)*a1 + FieldT(4)*a2 - FieldT(8)*a3) * (b0 - FieldT(2)*b1 + FieldT(4)*b2 - FieldT(8)*b3); + const FieldT v5 = (a0 + FieldT(3)*a1 + FieldT(9)*a2 + FieldT(27)*a3) * (b0 + FieldT(3)*b1 + FieldT(9)*b2 + FieldT(27)*b3); + const FieldT v6 = a3 * b3; + + const FieldT beta = Fp4T::non_residue; + + c0 = v0 + beta*(FieldT(4).inverse()*v0 - FieldT(6).inverse()*(v1 + v2) + FieldT(24).inverse() * (v3 + v4) - FieldT(5) * v6); + c1 = - FieldT(3).inverse()*v0 + v1 - FieldT(2).inverse()*v2 - FieldT(4).inverse()*v3 + FieldT(20).inverse() * v4 + FieldT(30).inverse() * v5 - FieldT(12) * v6 + beta * ( - FieldT(12).inverse() * (v0 - v1) + FieldT(24).inverse()*(v2 - v3) - FieldT(120).inverse() * (v4 - v5) - FieldT(3) * v6); + c2 = - (FieldT(5)*(FieldT(4).inverse()))* v0 + (FieldT(2)*(FieldT(3).inverse()))*(v1 + v2) - FieldT(24).inverse()*(v3 + v4) + FieldT(4)*v6 + beta*v6; + c3 = FieldT(12).inverse() * (FieldT(5)*v0 - FieldT(7)*v1) - FieldT(24).inverse()*(v2 - FieldT(7)*v3 + v4 + v5) + FieldT(15)*v6; + + assert(res == correct_res); + + // {v0, v3, v4, v5} + const FieldT u = (FieldT::one() - beta).inverse(); + assert(v0 == u * c0 + beta * u * c2 - beta * u * FieldT(2).inverse() * v1 - beta * u * FieldT(2).inverse() * v2 + beta * v6); + assert(v3 == - FieldT(15) * u * c0 - FieldT(30) * u * c1 - FieldT(3) * (FieldT(4) + beta) * u * c2 - FieldT(6) * (FieldT(4) + beta) * u * c3 + (FieldT(24) - FieldT(3) * beta * FieldT(2).inverse()) * u * v1 + (-FieldT(8) + beta * FieldT(2).inverse()) * u * v2 + - FieldT(3) * (-FieldT(16) + beta) * v6); + assert(v4 == - FieldT(15) * u * c0 + FieldT(30) * u * c1 - FieldT(3) * (FieldT(4) + beta) * u * c2 + FieldT(6) * (FieldT(4) + beta) * u * c3 + (FieldT(24) - FieldT(3) * beta * FieldT(2).inverse()) * u * v2 + (-FieldT(8) + beta * FieldT(2).inverse()) * u * v1 + - FieldT(3) * (-FieldT(16) + beta) * v6); + assert(v5 == - FieldT(80) * u * c0 - FieldT(240) * u * c1 - FieldT(8) * (FieldT(9) + beta) * u * c2 - FieldT(24) * (FieldT(9) + beta) * u * c3 - FieldT(2) * (-FieldT(81) + beta) * u * v1 + (-FieldT(81) + beta) * u * v2 + - FieldT(8) * (-FieldT(81) + beta) * v6); + + // c0 + beta c2 - (beta v1)/2 - (beta v2)/ 2 - (-1 + beta) beta v6, + // -15 c0 - 30 c1 - 3 (4 + beta) c2 - 6 (4 + beta) c3 + (24 - (3 beta)/2) v1 + (-8 + beta/2) v2 + 3 (-16 + beta) (-1 + beta) v6, + // -15 c0 + 30 c1 - 3 (4 + beta) c2 + 6 (4 + beta) c3 + (-8 + beta/2) v1 + (24 - (3 beta)/2) v2 + 3 (-16 + beta) (-1 + beta) v6, + // -80 c0 - 240 c1 - 8 (9 + beta) c2 - 24 (9 + beta) c3 - 2 (-81 + beta) v1 + (-81 + beta) v2 + 8 (-81 + beta) (-1 + beta) v6 + } +} + +int main(void) +{ + edwards_pp::init_public_params(); + test_all_fields(); + test_cyclotomic_squaring >(); + + mnt4_pp::init_public_params(); + test_all_fields(); + test_Fp4_tom_cook(); + test_two_squarings >(); + test_cyclotomic_squaring >(); + + mnt6_pp::init_public_params(); + test_all_fields(); + test_cyclotomic_squaring >(); + + alt_bn128_pp::init_public_params(); + test_field(); + test_Frobenius(); + test_all_fields(); + +#ifdef CURVE_BN128 // BN128 has fancy dependencies so it may be disabled + bn128_pp::init_public_params(); + test_field >(); + test_field >(); +#endif +} diff --git a/privacy/zsl/zsl/snark/libsnark/src/algebra/knowledge_commitment/knowledge_commitment.hpp b/privacy/zsl/zsl/snark/libsnark/src/algebra/knowledge_commitment/knowledge_commitment.hpp new file mode 100644 index 0000000..9024231 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/algebra/knowledge_commitment/knowledge_commitment.hpp @@ -0,0 +1,84 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for: + - a knowledge commitment, and + - a knowledge commitment vector. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef KNOWLEDGE_COMMITMENT_HPP_ +#define KNOWLEDGE_COMMITMENT_HPP_ + +#include "algebra/fields/fp.hpp" +#include "common/data_structures/sparse_vector.hpp" + +namespace libsnark { + +/********************** Knowledge commitment *********************************/ + +/** + * A knowledge commitment is a pair (g,h) where g is in T1 and h in T2, + * and T1 and T2 are groups (written additively). + * + * Such pairs form a group by defining: + * - "zero" = (0,0) + * - "one" = (1,1) + * - a * (g,h) + b * (g',h') := ( a * g + b * g', a * h + b * h'). + */ +template +struct knowledge_commitment { + + T1 g; + T2 h; + + knowledge_commitment() = default; + knowledge_commitment(const knowledge_commitment &other) = default; + knowledge_commitment(knowledge_commitment &&other) = default; + knowledge_commitment(const T1 &g, const T2 &h); + + knowledge_commitment& operator=(const knowledge_commitment &other) = default; + knowledge_commitment& operator=(knowledge_commitment &&other) = default; + knowledge_commitment operator+(const knowledge_commitment &other) const; + + bool is_zero() const; + bool operator==(const knowledge_commitment &other) const; + bool operator!=(const knowledge_commitment &other) const; + + static knowledge_commitment zero(); + static knowledge_commitment one(); + + void print() const; + + static size_t size_in_bits(); +}; + +template +knowledge_commitment operator*(const bigint &lhs, const knowledge_commitment &rhs); + +template &modulus_p> +knowledge_commitment operator*(const Fp_model &lhs, const knowledge_commitment &rhs); + +template +std::ostream& operator<<(std::ostream& out, const knowledge_commitment &kc); + +template +std::istream& operator>>(std::istream& in, knowledge_commitment &kc); + +/******************** Knowledge commitment vector ****************************/ + +/** + * A knowledge commitment vector is a sparse vector of knowledge commitments. + */ +template +using knowledge_commitment_vector = sparse_vector >; + +} // libsnark + +#include "algebra/knowledge_commitment/knowledge_commitment.tcc" + +#endif // KNOWLEDGE_COMMITMENT_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/algebra/knowledge_commitment/knowledge_commitment.tcc b/privacy/zsl/zsl/snark/libsnark/src/algebra/knowledge_commitment/knowledge_commitment.tcc new file mode 100644 index 0000000..15b2926 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/algebra/knowledge_commitment/knowledge_commitment.tcc @@ -0,0 +1,111 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for: + - a knowledge commitment, and + - a knowledge commitment vector. + + See knowledge_commitment.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef KNOWLEDGE_COMMITMENT_TCC_ +#define KNOWLEDGE_COMMITMENT_TCC_ + +namespace libsnark { + +template +knowledge_commitment::knowledge_commitment(const T1 &g, const T2 &h) : + g(g), h(h) +{ +} + +template +knowledge_commitment knowledge_commitment::zero() +{ + return knowledge_commitment(T1::zero(), T2::zero()); +} + +template +knowledge_commitment knowledge_commitment::one() +{ + return knowledge_commitment(T1::one(), T2::one()); +} + +template +knowledge_commitment knowledge_commitment::operator+(const knowledge_commitment &other) const +{ + return knowledge_commitment(this->g + other.g, + this->h + other.h); +} + +template +bool knowledge_commitment::is_zero() const +{ + return (g.is_zero() && h.is_zero()); +} + +template +bool knowledge_commitment::operator==(const knowledge_commitment &other) const +{ + return (this->g == other.g && + this->h == other.h); +} + +template +bool knowledge_commitment::operator!=(const knowledge_commitment &other) const +{ + return !((*this) == other); +} + +template +knowledge_commitment operator*(const bigint &lhs, const knowledge_commitment &rhs) +{ + return knowledge_commitment(lhs * rhs.g, + lhs * rhs.h); +} + +template &modulus_p> +knowledge_commitment operator*(const Fp_model &lhs, const knowledge_commitment &rhs) +{ + return (lhs.as_bigint()) * rhs; +} + +template +void knowledge_commitment::print() const +{ + printf("knowledge_commitment.g:\n"); + g.print(); + printf("knowledge_commitment.h:\n"); + h.print(); +} + +template +size_t knowledge_commitment::size_in_bits() +{ + return T1::size_in_bits() + T2::size_in_bits(); +} + +template +std::ostream& operator<<(std::ostream& out, const knowledge_commitment &kc) +{ + out << kc.g << OUTPUT_SEPARATOR << kc.h; + return out; +} + +template +std::istream& operator>>(std::istream& in, knowledge_commitment &kc) +{ + in >> kc.g; + consume_OUTPUT_SEPARATOR(in); + in >> kc.h; + return in; +} + +} // libsnark + +#endif // KNOWLEDGE_COMMITMENT_TCC_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/algebra/scalar_multiplication/kc_multiexp.hpp b/privacy/zsl/zsl/snark/libsnark/src/algebra/scalar_multiplication/kc_multiexp.hpp new file mode 100644 index 0000000..4e8b556 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/algebra/scalar_multiplication/kc_multiexp.hpp @@ -0,0 +1,55 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef KC_MULTIEXP_HPP_ +#define KC_MULTIEXP_HPP_ + +/* + Split out from multiexp to prevent cyclical + dependencies. I.e. previously multiexp dependend on + knowledge_commitment, which dependend on sparse_vector, which + dependend on multiexp (to do accumulate). + + Will probably go away in more general exp refactoring. +*/ + +#include "algebra/knowledge_commitment/knowledge_commitment.hpp" + +namespace libsnark { + +template +knowledge_commitment opt_window_wnaf_exp(const knowledge_commitment &base, + const bigint &scalar, const size_t scalar_bits); + +template +knowledge_commitment kc_multi_exp_with_mixed_addition(const knowledge_commitment_vector &vec, + const size_t min_idx, + const size_t max_idx, + typename std::vector::const_iterator scalar_start, + typename std::vector::const_iterator scalar_end, + const size_t chunks, + const bool use_multiexp=false); + +template +void kc_batch_to_special(std::vector > &vec); + +template +knowledge_commitment_vector kc_batch_exp(const size_t scalar_size, + const size_t T1_window, + const size_t T2_window, + const window_table &T1_table, + const window_table &T2_table, + const FieldT &T1_coeff, + const FieldT &T2_coeff, + const std::vector &v, + const size_t suggested_num_chunks); + +} // libsnark + +#include "algebra/scalar_multiplication/kc_multiexp.tcc" + +#endif // KC_MULTIEXP_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/algebra/scalar_multiplication/kc_multiexp.tcc b/privacy/zsl/zsl/snark/libsnark/src/algebra/scalar_multiplication/kc_multiexp.tcc new file mode 100644 index 0000000..e9c08d4 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/algebra/scalar_multiplication/kc_multiexp.tcc @@ -0,0 +1,274 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef KC_MULTIEXP_TCC_ +#define KC_MULTIEXP_TCC_ + +namespace libsnark { + +template +knowledge_commitment opt_window_wnaf_exp(const knowledge_commitment &base, + const bigint &scalar, const size_t scalar_bits) +{ + return knowledge_commitment(opt_window_wnaf_exp(base.g, scalar, scalar_bits), + opt_window_wnaf_exp(base.h, scalar, scalar_bits)); +} + +template +knowledge_commitment kc_multi_exp_with_mixed_addition(const knowledge_commitment_vector &vec, + const size_t min_idx, + const size_t max_idx, + typename std::vector::const_iterator scalar_start, + typename std::vector::const_iterator scalar_end, + const size_t chunks, + const bool use_multiexp) +{ + enter_block("Process scalar vector"); + auto index_it = std::lower_bound(vec.indices.begin(), vec.indices.end(), min_idx); + const size_t offset = index_it - vec.indices.begin(); + + auto value_it = vec.values.begin() + offset; + + const FieldT zero = FieldT::zero(); + const FieldT one = FieldT::one(); + + std::vector p; + std::vector > g; + + knowledge_commitment acc = knowledge_commitment::zero(); + + size_t num_skip = 0; + size_t num_add = 0; + size_t num_other = 0; + + const size_t scalar_length = std::distance(scalar_start, scalar_end); + + while (index_it != vec.indices.end() && *index_it < max_idx) + { + const size_t scalar_position = (*index_it) - min_idx; + assert(scalar_position < scalar_length); + + const FieldT scalar = *(scalar_start + scalar_position); + + if (scalar == zero) + { + // do nothing + ++num_skip; + } + else if (scalar == one) + { +#ifdef USE_MIXED_ADDITION + acc.g = acc.g.mixed_add(value_it->g); + acc.h = acc.h.mixed_add(value_it->h); +#else + acc.g = acc.g + value_it->g; + acc.h = acc.h + value_it->h; +#endif + ++num_add; + } + else + { + p.emplace_back(scalar); + g.emplace_back(*value_it); + ++num_other; + } + + ++index_it; + ++value_it; + } + + //print_indent(); printf("* Elements of w skipped: %zu (%0.2f%%)\n", num_skip, 100.*num_skip/(num_skip+num_add+num_other)); + //print_indent(); printf("* Elements of w processed with special addition: %zu (%0.2f%%)\n", num_add, 100.*num_add/(num_skip+num_add+num_other)); + //print_indent(); printf("* Elements of w remaining: %zu (%0.2f%%)\n", num_other, 100.*num_other/(num_skip+num_add+num_other)); + leave_block("Process scalar vector"); + + return acc + multi_exp, FieldT>(g.begin(), g.end(), p.begin(), p.end(), chunks, use_multiexp); +} + +template +void kc_batch_to_special(std::vector > &vec) +{ + enter_block("Batch-convert knowledge-commitments to special form"); + + std::vector g_vec; + g_vec.reserve(vec.size()); + + for (size_t i = 0; i < vec.size(); ++i) + { + if (!vec[i].g.is_zero()) + { + g_vec.emplace_back(vec[i].g); + } + } + + batch_to_special_all_non_zeros(g_vec); + auto g_it = g_vec.begin(); + T1 T1_zero_special = T1::zero(); + T1_zero_special.to_special(); + + for (size_t i = 0; i < vec.size(); ++i) + { + if (!vec[i].g.is_zero()) + { + vec[i].g = *g_it; + ++g_it; + } + else + { + vec[i].g = T1_zero_special; + } + } + + g_vec.clear(); + + std::vector h_vec; + h_vec.reserve(vec.size()); + + for (size_t i = 0; i < vec.size(); ++i) + { + if (!vec[i].h.is_zero()) + { + h_vec.emplace_back(vec[i].h); + } + } + + batch_to_special_all_non_zeros(h_vec); + auto h_it = h_vec.begin(); + T2 T2_zero_special = T2::zero(); + T2_zero_special.to_special(); + + for (size_t i = 0; i < vec.size(); ++i) + { + if (!vec[i].h.is_zero()) + { + vec[i].h = *h_it; + ++h_it; + } + else + { + vec[i].h = T2_zero_special; + } + } + + g_vec.clear(); + + leave_block("Batch-convert knowledge-commitments to special form"); +} + +template +knowledge_commitment_vector kc_batch_exp_internal(const size_t scalar_size, + const size_t T1_window, + const size_t T2_window, + const window_table &T1_table, + const window_table &T2_table, + const FieldT &T1_coeff, + const FieldT &T2_coeff, + const std::vector &v, + const size_t start_pos, + const size_t end_pos, + const size_t expected_size) +{ + knowledge_commitment_vector res; + + res.values.reserve(expected_size); + res.indices.reserve(expected_size); + + for (size_t pos = start_pos; pos != end_pos; ++pos) + { + if (!v[pos].is_zero()) + { + res.values.emplace_back(knowledge_commitment(windowed_exp(scalar_size, T1_window, T1_table, T1_coeff * v[pos]), + windowed_exp(scalar_size, T2_window, T2_table, T2_coeff * v[pos]))); + res.indices.emplace_back(pos); + } + } + + return res; +} + +template +knowledge_commitment_vector kc_batch_exp(const size_t scalar_size, + const size_t T1_window, + const size_t T2_window, + const window_table &T1_table, + const window_table &T2_table, + const FieldT &T1_coeff, + const FieldT &T2_coeff, + const std::vector &v, + const size_t suggested_num_chunks) +{ + knowledge_commitment_vector res; + res.domain_size_ = v.size(); + + size_t nonzero = 0; + for (size_t i = 0; i < v.size(); ++i) + { + nonzero += (v[i].is_zero() ? 0 : 1); + } + + const size_t num_chunks = std::max((size_t)1, std::min(nonzero, suggested_num_chunks)); + + if (!inhibit_profiling_info) + { + print_indent(); printf("Non-zero coordinate count: %zu/%zu (%0.2f%%)\n", nonzero, v.size(), 100.*nonzero/v.size()); + } + + std::vector > tmp(num_chunks); + std::vector chunk_pos(num_chunks+1); + + const size_t chunk_size = nonzero / num_chunks; + const size_t last_chunk = nonzero - chunk_size * (num_chunks - 1); + + chunk_pos[0] = 0; + + size_t cnt = 0; + size_t chunkno = 1; + + for (size_t i = 0; i < v.size(); ++i) + { + cnt += (v[i].is_zero() ? 0 : 1); + if (cnt == chunk_size && chunkno < num_chunks) + { + chunk_pos[chunkno] = i; + cnt = 0; + ++chunkno; + } + } + + chunk_pos[num_chunks] = v.size(); + +#ifdef MULTICORE +#pragma omp parallel for +#endif + for (size_t i = 0; i < num_chunks; ++i) + { + tmp[i] = kc_batch_exp_internal(scalar_size, T1_window, T2_window, T1_table, T2_table, T1_coeff, T2_coeff, v, + chunk_pos[i], chunk_pos[i+1], i == num_chunks - 1 ? last_chunk : chunk_size); +#ifdef USE_MIXED_ADDITION + kc_batch_to_special(tmp[i].values); +#endif + } + + if (num_chunks == 1) + { + tmp[0].domain_size_ = v.size(); + return tmp[0]; + } + else + { + for (size_t i = 0; i < num_chunks; ++i) + { + res.values.insert(res.values.end(), tmp[i].values.begin(), tmp[i].values.end()); + res.indices.insert(res.indices.end(), tmp[i].indices.begin(), tmp[i].indices.end()); + } + return res; + } +} + +} // libsnark + +#endif // KC_MULTIEXP_TCC_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/algebra/scalar_multiplication/multiexp.hpp b/privacy/zsl/zsl/snark/libsnark/src/algebra/scalar_multiplication/multiexp.hpp new file mode 100644 index 0000000..eaf72d6 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/algebra/scalar_multiplication/multiexp.hpp @@ -0,0 +1,110 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for multi-exponentiation routines. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef MULTIEXP_HPP_ +#define MULTIEXP_HPP_ + +namespace libsnark { + +/** + * Naive multi-exponentiation individually multiplies each base by the + * corresponding scalar and adds up the results. + */ +template +T naive_exp(typename std::vector::const_iterator vec_start, + typename std::vector::const_iterator vec_end, + typename std::vector::const_iterator scalar_start, + typename std::vector::const_iterator scalar_end); + +template +T naive_plain_exp(typename std::vector::const_iterator vec_start, + typename std::vector::const_iterator vec_end, + typename std::vector::const_iterator scalar_start, + typename std::vector::const_iterator scalar_end); + +/** + * Naive multi-exponentiation uses a variant of the Bos-Coster algorithm [1], + * and implementation suggestions from [2]. + * + * [1] = Bos and Coster, "Addition chain heuristics", CRYPTO '89 + * [2] = Bernstein, Duif, Lange, Schwabe, and Yang, "High-speed high-security signatures", CHES '11 + */ +template +T multi_exp(typename std::vector::const_iterator vec_start, + typename std::vector::const_iterator vec_end, + typename std::vector::const_iterator scalar_start, + typename std::vector::const_iterator scalar_end, + const size_t chunks, + const bool use_multiexp=false); + + +/** + * A variant of multi_exp that takes advantage of the method mixed_add (instead of the operator '+'). + */ +template +T multi_exp_with_mixed_addition(typename std::vector::const_iterator vec_start, + typename std::vector::const_iterator vec_end, + typename std::vector::const_iterator scalar_start, + typename std::vector::const_iterator scalar_end, + const size_t chunks, + const bool use_multiexp); + +/** + * A window table stores window sizes for different instance sizes for fixed-base multi-scalar multiplications. + */ +template +using window_table = std::vector >; + +/** + * Compute window size for the given number of scalars. + */ +template +size_t get_exp_window_size(const size_t num_scalars); + +/** + * Compute table of window sizes. + */ +template +window_table get_window_table(const size_t scalar_size, + const size_t window, + const T &g); + +template +T windowed_exp(const size_t scalar_size, + const size_t window, + const window_table &powers_of_g, + const FieldT &pow); + +template +std::vector batch_exp(const size_t scalar_size, + const size_t window, + const window_table &table, + const std::vector &v); + +template +std::vector batch_exp_with_coeff(const size_t scalar_size, + const size_t window, + const window_table &table, + const FieldT &coeff, + const std::vector &v); + +// defined in every curve +template +void batch_to_special_all_non_zeros(std::vector &vec); + +template +void batch_to_special(std::vector &vec); + +} // libsnark + +#include "algebra/scalar_multiplication/multiexp.tcc" + +#endif // MULTIEXP_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/algebra/scalar_multiplication/multiexp.tcc b/privacy/zsl/zsl/snark/libsnark/src/algebra/scalar_multiplication/multiexp.tcc new file mode 100644 index 0000000..a6b14c4 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/algebra/scalar_multiplication/multiexp.tcc @@ -0,0 +1,590 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for multi-exponentiation routines. + + See multiexp.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef MULTIEXP_TCC_ +#define MULTIEXP_TCC_ + +#include "algebra/fields/fp_aux.tcc" + +#include +#include +#include + +#include "common/profiling.hpp" +#include "common/utils.hpp" +#include "algebra/scalar_multiplication/wnaf.hpp" + +namespace libsnark { + +template +class ordered_exponent { +// to use std::push_heap and friends later +public: + size_t idx; + bigint r; + + ordered_exponent(const size_t idx, const bigint &r) : idx(idx), r(r) {}; + + bool operator<(const ordered_exponent &other) const + { +#if defined(__x86_64__) && defined(USE_ASM) + if (n == 3) + { + long res; + __asm__ + ("// check for overflow \n\t" + "mov $0, %[res] \n\t" + ADD_CMP(16) + ADD_CMP(8) + ADD_CMP(0) + "jmp done%= \n\t" + "subtract%=: \n\t" + "mov $1, %[res] \n\t" + "done%=: \n\t" + : [res] "=&r" (res) + : [A] "r" (other.r.data), [mod] "r" (this->r.data) + : "cc", "%rax"); + return res; + } + else if (n == 4) + { + long res; + __asm__ + ("// check for overflow \n\t" + "mov $0, %[res] \n\t" + ADD_CMP(24) + ADD_CMP(16) + ADD_CMP(8) + ADD_CMP(0) + "jmp done%= \n\t" + "subtract%=: \n\t" + "mov $1, %[res] \n\t" + "done%=: \n\t" + : [res] "=&r" (res) + : [A] "r" (other.r.data), [mod] "r" (this->r.data) + : "cc", "%rax"); + return res; + } + else if (n == 5) + { + long res; + __asm__ + ("// check for overflow \n\t" + "mov $0, %[res] \n\t" + ADD_CMP(32) + ADD_CMP(24) + ADD_CMP(16) + ADD_CMP(8) + ADD_CMP(0) + "jmp done%= \n\t" + "subtract%=: \n\t" + "mov $1, %[res] \n\t" + "done%=: \n\t" + : [res] "=&r" (res) + : [A] "r" (other.r.data), [mod] "r" (this->r.data) + : "cc", "%rax"); + return res; + } + else +#endif + { + return (mpn_cmp(this->r.data, other.r.data, n) < 0); + } + } +}; + +template +T naive_exp(typename std::vector::const_iterator vec_start, + typename std::vector::const_iterator vec_end, + typename std::vector::const_iterator scalar_start, + typename std::vector::const_iterator scalar_end) +{ + T result(T::zero()); + + typename std::vector::const_iterator vec_it; + typename std::vector::const_iterator scalar_it; + + for (vec_it = vec_start, scalar_it = scalar_start; vec_it != vec_end; ++vec_it, ++scalar_it) + { + bigint scalar_bigint = scalar_it->as_bigint(); + result = result + opt_window_wnaf_exp(*vec_it, scalar_bigint, scalar_bigint.num_bits()); + } + assert(scalar_it == scalar_end); + + return result; +} + +template +T naive_plain_exp(typename std::vector::const_iterator vec_start, + typename std::vector::const_iterator vec_end, + typename std::vector::const_iterator scalar_start, + typename std::vector::const_iterator scalar_end) +{ + T result(T::zero()); + + typename std::vector::const_iterator vec_it; + typename std::vector::const_iterator scalar_it; + + for (vec_it = vec_start, scalar_it = scalar_start; vec_it != vec_end; ++vec_it, ++scalar_it) + { + result = result + (*scalar_it) * (*vec_it); + } + assert(scalar_it == scalar_end); + + return result; +} + +/* + The multi-exponentiation algorithm below is a variant of the Bos-Coster algorithm + [Bos and Coster, "Addition chain heuristics", CRYPTO '89]. + The implementation uses suggestions from + [Bernstein, Duif, Lange, Schwabe, and Yang, "High-speed high-security signatures", CHES '11]. +*/ +template +T multi_exp_inner(typename std::vector::const_iterator vec_start, + typename std::vector::const_iterator vec_end, + typename std::vector::const_iterator scalar_start, + typename std::vector::const_iterator scalar_end) +{ + const mp_size_t n = std::remove_reference::type::num_limbs; + + if (vec_start == vec_end) + { + return T::zero(); + } + + if (vec_start + 1 == vec_end) + { + return (*scalar_start)*(*vec_start); + } + + std::vector > opt_q; + const size_t vec_len = scalar_end - scalar_start; + const size_t odd_vec_len = (vec_len % 2 == 1 ? vec_len : vec_len + 1); + opt_q.reserve(odd_vec_len); + std::vector g; + g.reserve(odd_vec_len); + + typename std::vector::const_iterator vec_it; + typename std::vector::const_iterator scalar_it; + size_t i; + for (i=0, vec_it = vec_start, scalar_it = scalar_start; vec_it != vec_end; ++vec_it, ++scalar_it, ++i) + { + g.emplace_back(*vec_it); + + opt_q.emplace_back(ordered_exponent(i, scalar_it->as_bigint())); + } + std::make_heap(opt_q.begin(),opt_q.end()); + assert(scalar_it == scalar_end); + + if (vec_len != odd_vec_len) + { + g.emplace_back(T::zero()); + opt_q.emplace_back(ordered_exponent(odd_vec_len - 1, bigint(0ul))); + } + assert(g.size() % 2 == 1); + assert(opt_q.size() == g.size()); + + T opt_result = T::zero(); + + while (true) + { + ordered_exponent &a = opt_q[0]; + ordered_exponent &b = (opt_q[1] < opt_q[2] ? opt_q[2] : opt_q[1]); + + const size_t abits = a.r.num_bits(); + + if (b.r.is_zero()) + { + // opt_result = opt_result + (a.r * g[a.idx]); + opt_result = opt_result + opt_window_wnaf_exp(g[a.idx], a.r, abits); + break; + } + + const size_t bbits = b.r.num_bits(); + const size_t limit = (abits-bbits >= 20 ? 20 : abits-bbits); + + if (bbits < 1ul< (x-y) A + y (B+A) + mpn_sub_n(a.r.data, a.r.data, b.r.data, n); + g[b.idx] = g[b.idx] + g[a.idx]; + } + + // regardless of whether a was cleared or subtracted from we push it down, then take back up + + /* heapify A down */ + size_t a_pos = 0; + while (2*a_pos + 2< odd_vec_len) + { + // this is a max-heap so to maintain a heap property we swap with the largest of the two + if (opt_q[2*a_pos+1] < opt_q[2*a_pos+2]) + { + std::swap(opt_q[a_pos], opt_q[2*a_pos+2]); + a_pos = 2*a_pos+2; + } + else + { + std::swap(opt_q[a_pos], opt_q[2*a_pos+1]); + a_pos = 2*a_pos+1; + } + } + + /* now heapify A up appropriate amount of times */ + while (a_pos > 0 && opt_q[(a_pos-1)/2] < opt_q[a_pos]) + { + std::swap(opt_q[a_pos], opt_q[(a_pos-1)/2]); + a_pos = (a_pos-1) / 2; + } + } + + return opt_result; +} + +template +T multi_exp(typename std::vector::const_iterator vec_start, + typename std::vector::const_iterator vec_end, + typename std::vector::const_iterator scalar_start, + typename std::vector::const_iterator scalar_end, + const size_t chunks, + const bool use_multiexp) +{ + const size_t total = vec_end - vec_start; + if (total < chunks) + { + return naive_exp(vec_start, vec_end, scalar_start, scalar_end); + } + + const size_t one = total/chunks; + + std::vector partial(chunks, T::zero()); + + if (use_multiexp) + { +#ifdef MULTICORE +#pragma omp parallel for +#endif + for (size_t i = 0; i < chunks; ++i) + { + partial[i] = multi_exp_inner(vec_start + i*one, + (i == chunks-1 ? vec_end : vec_start + (i+1)*one), + scalar_start + i*one, + (i == chunks-1 ? scalar_end : scalar_start + (i+1)*one)); + } + } + else + { +#ifdef MULTICORE +#pragma omp parallel for +#endif + for (size_t i = 0; i < chunks; ++i) + { + partial[i] = naive_exp(vec_start + i*one, + (i == chunks-1 ? vec_end : vec_start + (i+1)*one), + scalar_start + i*one, + (i == chunks-1 ? scalar_end : scalar_start + (i+1)*one)); + } + } + + T final = T::zero(); + + for (size_t i = 0; i < chunks; ++i) + { + final = final + partial[i]; + } + + return final; +} + +template +T multi_exp_with_mixed_addition(typename std::vector::const_iterator vec_start, + typename std::vector::const_iterator vec_end, + typename std::vector::const_iterator scalar_start, + typename std::vector::const_iterator scalar_end, + const size_t chunks, + const bool use_multiexp) +{ + assert(std::distance(vec_start, vec_end) == std::distance(scalar_start, scalar_end)); + enter_block("Process scalar vector"); + auto value_it = vec_start; + auto scalar_it = scalar_start; + + const FieldT zero = FieldT::zero(); + const FieldT one = FieldT::one(); + std::vector p; + std::vector g; + + T acc = T::zero(); + + size_t num_skip = 0; + size_t num_add = 0; + size_t num_other = 0; + + for (; scalar_it != scalar_end; ++scalar_it, ++value_it) + { + if (*scalar_it == zero) + { + // do nothing + ++num_skip; + } + else if (*scalar_it == one) + { +#ifdef USE_MIXED_ADDITION + acc = acc.mixed_add(*value_it); +#else + acc = acc + (*value_it); +#endif + ++num_add; + } + else + { + p.emplace_back(*scalar_it); + g.emplace_back(*value_it); + ++num_other; + } + } + //print_indent(); printf("* Elements of w skipped: %zu (%0.2f%%)\n", num_skip, 100.*num_skip/(num_skip+num_add+num_other)); + //print_indent(); printf("* Elements of w processed with special addition: %zu (%0.2f%%)\n", num_add, 100.*num_add/(num_skip+num_add+num_other)); + //print_indent(); printf("* Elements of w remaining: %zu (%0.2f%%)\n", num_other, 100.*num_other/(num_skip+num_add+num_other)); + + leave_block("Process scalar vector"); + + return acc + multi_exp(g.begin(), g.end(), p.begin(), p.end(), chunks, use_multiexp); +} + +template +size_t get_exp_window_size(const size_t num_scalars) +{ + if (T::fixed_base_exp_window_table.empty()) + { +#ifdef LOWMEM + return 14; +#else + return 17; +#endif + } + size_t window = 1; + for (long i = T::fixed_base_exp_window_table.size()-1; i >= 0; --i) + { +#ifdef DEBUG + if (!inhibit_profiling_info) + { + printf("%ld %zu %zu\n", i, num_scalars, T::fixed_base_exp_window_table[i]); + } +#endif + if (T::fixed_base_exp_window_table[i] != 0 && num_scalars >= T::fixed_base_exp_window_table[i]) + { + window = i+1; + break; + } + } + + if (!inhibit_profiling_info) + { + print_indent(); printf("Choosing window size %zu for %zu elements\n", window, num_scalars); + } + +#ifdef LOWMEM + window = std::min((size_t)14, window); +#endif + return window; +} + +template +window_table get_window_table(const size_t scalar_size, + const size_t window, + const T &g) +{ + const size_t in_window = 1ul< powers_of_g(outerc, std::vector(in_window, T::zero())); + + T gouter = g; + + for (size_t outer = 0; outer < outerc; ++outer) + { + T ginner = T::zero(); + size_t cur_in_window = outer == outerc-1 ? last_in_window : in_window; + for (size_t inner = 0; inner < cur_in_window; ++inner) + { + powers_of_g[outer][inner] = ginner; + ginner = ginner + gouter; + } + + for (size_t i = 0; i < window; ++i) + { + gouter = gouter + gouter; + } + } + + return powers_of_g; +} + +template +T windowed_exp(const size_t scalar_size, + const size_t window, + const window_table &powers_of_g, + const FieldT &pow) +{ + const size_t outerc = (scalar_size+window-1)/window; + const bigint pow_val = pow.as_bigint(); + + /* exp */ + T res = powers_of_g[0][0]; + + for (size_t outer = 0; outer < outerc; ++outer) + { + size_t inner = 0; + for (size_t i = 0; i < window; ++i) + { + if (pow_val.test_bit(outer*window + i)) + { + inner |= 1u << i; + } + } + + res = res + powers_of_g[outer][inner]; + } + + return res; +} + +template +std::vector batch_exp(const size_t scalar_size, + const size_t window, + const window_table &table, + const std::vector &v) +{ + if (!inhibit_profiling_info) + { + print_indent(); + } + std::vector res(v.size(), table[0][0]); + +#ifdef MULTICORE +#pragma omp parallel for +#endif + for (size_t i = 0; i < v.size(); ++i) + { + res[i] = windowed_exp(scalar_size, window, table, v[i]); + + if (!inhibit_profiling_info && (i % 10000 == 0)) + { + printf("."); + fflush(stdout); + } + } + + if (!inhibit_profiling_info) + { + printf(" DONE!\n"); + } + + return res; +} + +template +std::vector batch_exp_with_coeff(const size_t scalar_size, + const size_t window, + const window_table &table, + const FieldT &coeff, + const std::vector &v) +{ + if (!inhibit_profiling_info) + { + print_indent(); + } + std::vector res(v.size(), table[0][0]); + +#ifdef MULTICORE +#pragma omp parallel for +#endif + for (size_t i = 0; i < v.size(); ++i) + { + res[i] = windowed_exp(scalar_size, window, table, coeff * v[i]); + + if (!inhibit_profiling_info && (i % 10000 == 0)) + { + printf("."); + fflush(stdout); + } + } + + if (!inhibit_profiling_info) + { + printf(" DONE!\n"); + } + + return res; +} + +template +void batch_to_special(std::vector &vec) +{ + enter_block("Batch-convert elements to special form"); + + std::vector non_zero_vec; + for (size_t i = 0; i < vec.size(); ++i) + { + if (!vec[i].is_zero()) + { + non_zero_vec.emplace_back(vec[i]); + } + } + + batch_to_special_all_non_zeros(non_zero_vec); + auto it = non_zero_vec.begin(); + T zero_special = T::zero(); + zero_special.to_special(); + + for (size_t i = 0; i < vec.size(); ++i) + { + if (!vec[i].is_zero()) + { + vec[i] = *it; + ++it; + } + else + { + vec[i] = zero_special; + } + } + leave_block("Batch-convert elements to special form"); +} + +} // libsnark + +#endif // MULTIEXP_TCC_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/algebra/scalar_multiplication/wnaf.hpp b/privacy/zsl/zsl/snark/libsnark/src/algebra/scalar_multiplication/wnaf.hpp new file mode 100644 index 0000000..a7ecd59 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/algebra/scalar_multiplication/wnaf.hpp @@ -0,0 +1,39 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for wNAF ("width-w Non-Adjacent Form") exponentiation routines. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef WNAF_HPP_ +#define WNAF_HPP_ + +namespace libsnark { + +/** + * Find the wNAF representation of the given scalar relative to the given window size. + */ +template +std::vector find_wnaf(const size_t window_size, const bigint &scalar); + +/** + * In additive notation, use wNAF exponentiation (with the given window size) to compute scalar * base. + */ +template +T fixed_window_wnaf_exp(const size_t window_size, const T &base, const bigint &scalar); + +/** + * In additive notation, use wNAF exponentiation (with the window size determined by T) to compute scalar * base. + */ +template +T opt_window_wnaf_exp(const T &base, const bigint &scalar, const size_t scalar_bits); + +} // libsnark + +#include "algebra/scalar_multiplication/wnaf.tcc" + +#endif // WNAF_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/algebra/scalar_multiplication/wnaf.tcc b/privacy/zsl/zsl/snark/libsnark/src/algebra/scalar_multiplication/wnaf.tcc new file mode 100644 index 0000000..a5e47e8 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/algebra/scalar_multiplication/wnaf.tcc @@ -0,0 +1,123 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for wNAF ("weighted Non-Adjacent Form") exponentiation routines. + + See wnaf.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef WNAF_TCC_ +#define WNAF_TCC_ + +namespace libsnark { + +template +std::vector find_wnaf(const size_t window_size, const bigint &scalar) +{ + const size_t length = scalar.max_bits(); // upper bound + std::vector res(length+1); + bigint c = scalar; + long j = 0; + while (!c.is_zero()) + { + long u; + if ((c.data[0] & 1) == 1) + { + u = c.data[0] % (1u << (window_size+1)); + if (u > (1 << window_size)) + { + u = u - (1 << (window_size+1)); + } + + if (u > 0) + { + mpn_sub_1(c.data, c.data, n, u); + } + else + { + mpn_add_1(c.data, c.data, n, -u); + } + } + else + { + u = 0; + } + res[j] = u; + ++j; + + mpn_rshift(c.data, c.data, n, 1); // c = c/2 + } + + return res; +} + +template +T fixed_window_wnaf_exp(const size_t window_size, const T &base, const bigint &scalar) +{ + std::vector naf = find_wnaf(window_size, scalar); + std::vector table(1ul<<(window_size-1)); + T tmp = base; + T dbl = base.dbl(); + for (size_t i = 0; i < 1ul<<(window_size-1); ++i) + { + table[i] = tmp; + tmp = tmp + dbl; + } + + T res = T::zero(); + bool found_nonzero = false; + for (long i = naf.size()-1; i >= 0; --i) + { + if (found_nonzero) + { + res = res.dbl(); + } + + if (naf[i] != 0) + { + found_nonzero = true; + if (naf[i] > 0) + { + res = res + table[naf[i]/2]; + } + else + { + res = res - table[(-naf[i])/2]; + } + } + } + + return res; +} + +template +T opt_window_wnaf_exp(const T &base, const bigint &scalar, const size_t scalar_bits) +{ + size_t best = 0; + for (long i = T::wnaf_window_table.size() - 1; i >= 0; --i) + { + if (scalar_bits >= T::wnaf_window_table[i]) + { + best = i+1; + break; + } + } + + if (best > 0) + { + return fixed_window_wnaf_exp(best, base, scalar); + } + else + { + return scalar * base; + } +} + +} // libsnark + +#endif // WNAF_TCC_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/common/data_structures/accumulation_vector.hpp b/privacy/zsl/zsl/snark/libsnark/src/common/data_structures/accumulation_vector.hpp new file mode 100644 index 0000000..d46b406 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/common/data_structures/accumulation_vector.hpp @@ -0,0 +1,74 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for an accumulation vector. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef ACCUMULATION_VECTOR_HPP_ +#define ACCUMULATION_VECTOR_HPP_ + +#include "common/data_structures/sparse_vector.hpp" + +namespace libsnark { + +template +class accumulation_vector; + +template +std::ostream& operator<<(std::ostream &out, const accumulation_vector &v); + +template +std::istream& operator>>(std::istream &in, accumulation_vector &v); + +/** + * An accumulation vector comprises an accumulation value and a sparse vector. + * The method "accumulate_chunk" allows one to accumulate portions of the sparse + * vector into the accumulation value. + */ +template +class accumulation_vector { +public: + T first; + sparse_vector rest; + + accumulation_vector() = default; + accumulation_vector(const accumulation_vector &other) = default; + accumulation_vector(accumulation_vector &&other) = default; + accumulation_vector(T &&first, sparse_vector &&rest) : first(std::move(first)), rest(std::move(rest)) {}; + accumulation_vector(T &&first, std::vector &&v) : first(std::move(first)), rest(std::move(v)) {} + accumulation_vector(std::vector &&v) : first(T::zero()), rest(std::move(v)) {}; + + accumulation_vector& operator=(const accumulation_vector &other) = default; + accumulation_vector& operator=(accumulation_vector &&other) = default; + + bool operator==(const accumulation_vector &other) const; + + bool is_fully_accumulated() const; + + size_t domain_size() const; + size_t size() const; + size_t size_in_bits() const; + + template + accumulation_vector accumulate_chunk(const typename std::vector::const_iterator &it_begin, + const typename std::vector::const_iterator &it_end, + const size_t offset) const; + +}; + +template +std::ostream& operator<<(std::ostream &out, const accumulation_vector &v); + +template +std::istream& operator>>(std::istream &in, accumulation_vector &v); + +} // libsnark + +#include "common/data_structures/accumulation_vector.tcc" + +#endif // ACCUMULATION_VECTOR_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/common/data_structures/accumulation_vector.tcc b/privacy/zsl/zsl/snark/libsnark/src/common/data_structures/accumulation_vector.tcc new file mode 100644 index 0000000..9e524ab --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/common/data_structures/accumulation_vector.tcc @@ -0,0 +1,84 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for an accumulation vector. + + See accumulation_vector.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef ACCUMULATION_VECTOR_TCC_ +#define ACCUMULATION_VECTOR_TCC_ + +namespace libsnark { + +template +bool accumulation_vector::operator==(const accumulation_vector &other) const +{ + return (this->first == other.first && this->rest == other.rest); +} + +template +bool accumulation_vector::is_fully_accumulated() const +{ + return rest.empty(); +} + +template +size_t accumulation_vector::domain_size() const +{ + return rest.domain_size(); +} + +template +size_t accumulation_vector::size() const +{ + return rest.domain_size(); +} + +template +size_t accumulation_vector::size_in_bits() const +{ + const size_t first_size_in_bits = T::size_in_bits(); + const size_t rest_size_in_bits = rest.size_in_bits(); + return first_size_in_bits + rest_size_in_bits; +} + +template +template +accumulation_vector accumulation_vector::accumulate_chunk(const typename std::vector::const_iterator &it_begin, + const typename std::vector::const_iterator &it_end, + const size_t offset) const +{ + std::pair > acc_result = rest.template accumulate(it_begin, it_end, offset); + T new_first = first + acc_result.first; + return accumulation_vector(std::move(new_first), std::move(acc_result.second)); +} + +template +std::ostream& operator<<(std::ostream& out, const accumulation_vector &v) +{ + out << v.first << OUTPUT_NEWLINE; + out << v.rest << OUTPUT_NEWLINE; + + return out; +} + +template +std::istream& operator>>(std::istream& in, accumulation_vector &v) +{ + in >> v.first; + consume_OUTPUT_NEWLINE(in); + in >> v.rest; + consume_OUTPUT_NEWLINE(in); + + return in; +} + +} // libsnark + +#endif // ACCUMULATION_VECTOR_TCC_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/common/data_structures/integer_permutation.cpp b/privacy/zsl/zsl/snark/libsnark/src/common/data_structures/integer_permutation.cpp new file mode 100644 index 0000000..378ea7e --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/common/data_structures/integer_permutation.cpp @@ -0,0 +1,121 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for a permutation of the integers in {min_element,...,max_element}. + + See integer_permutation.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include "common/data_structures/integer_permutation.hpp" + +#include +#include +#include +#include + +namespace libsnark { + +integer_permutation::integer_permutation(const size_t size) : + min_element(0), max_element(size-1) +{ + contents.resize(size); + std::iota(contents.begin(), contents.end(), 0); +} + +integer_permutation::integer_permutation(const size_t min_element, const size_t max_element) : + min_element(min_element), max_element(max_element) +{ + assert(min_element <= max_element); + const size_t size = max_element - min_element + 1; + contents.resize(size); + std::iota(contents.begin(), contents.end(), min_element); +} + +size_t integer_permutation::size() const +{ + return max_element - min_element + 1; +} + +bool integer_permutation::operator==(const integer_permutation &other) const +{ + return (this->min_element == other.min_element && + this->max_element == other.max_element && + this->contents == other.contents); +} + +void integer_permutation::set(const size_t position, const size_t value) +{ + assert(min_element <= position && position <= max_element); + contents[position - min_element] = value; +} + +size_t integer_permutation::get(const size_t position) const +{ + assert(min_element <= position && position <= max_element); + return contents[position - min_element]; +} + + +bool integer_permutation::is_valid() const +{ + std::unordered_set elems; + + for (auto &el : contents) + { + if (el < min_element || el > max_element || elems.find(el) != elems.end()) + { + return false; + } + + elems.insert(el); + } + + return true; +} + +integer_permutation integer_permutation::inverse() const +{ + integer_permutation result(min_element, max_element); + + for (size_t position = min_element; position <= max_element; ++position) + { + result.contents[this->contents[position - min_element] - min_element] = position; + } + +#ifdef DEBUG + assert(result.is_valid()); +#endif + + return result; +} + +integer_permutation integer_permutation::slice(const size_t slice_min_element, const size_t slice_max_element) const +{ + assert(min_element <= slice_min_element && slice_min_element <= slice_max_element && slice_max_element <= max_element); + integer_permutation result(slice_min_element, slice_max_element); + std::copy(this->contents.begin() + (slice_min_element - min_element), + this->contents.begin() + (slice_max_element - min_element) + 1, + result.contents.begin()); +#ifdef DEBUG + assert(result.is_valid()); +#endif + + return result; +} + +bool integer_permutation::next_permutation() +{ + return std::next_permutation(contents.begin(), contents.end()); +} + +void integer_permutation::random_shuffle() +{ + return std::random_shuffle(contents.begin(), contents.end()); +} + +} // libsnark diff --git a/privacy/zsl/zsl/snark/libsnark/src/common/data_structures/integer_permutation.hpp b/privacy/zsl/zsl/snark/libsnark/src/common/data_structures/integer_permutation.hpp new file mode 100644 index 0000000..f55a750 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/common/data_structures/integer_permutation.hpp @@ -0,0 +1,54 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for a permutation of the integers in {min_element,...,max_element}. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef INTEGER_PERMUTATION_HPP_ +#define INTEGER_PERMUTATION_HPP_ + +#include +#include + +namespace libsnark { + +class integer_permutation { +private: + std::vector contents; /* offset by min_element */ + +public: + size_t min_element; + size_t max_element; + + integer_permutation(const size_t size = 0); + integer_permutation(const size_t min_element, const size_t max_element); + + integer_permutation& operator=(const integer_permutation &other) = default; + + size_t size() const; + bool operator==(const integer_permutation &other) const; + + void set(const size_t position, const size_t value); + size_t get(const size_t position) const; + + bool is_valid() const; + integer_permutation inverse() const; + integer_permutation slice(const size_t slice_min_element, const size_t slice_max_element) const; + + /* Similarly to std::next_permutation this transforms the current + integer permutation into the next lexicographically oredered + permutation; returns false if the last permutation was reached and + this is now the identity permutation on [min_element .. max_element] */ + bool next_permutation(); + + void random_shuffle(); +}; + +} // libsnark + +#endif // INTEGER_PERMUTATION_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/common/data_structures/merkle_tree.hpp b/privacy/zsl/zsl/snark/libsnark/src/common/data_structures/merkle_tree.hpp new file mode 100644 index 0000000..6f0c851 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/common/data_structures/merkle_tree.hpp @@ -0,0 +1,71 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for a Merkle tree. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef MERKLE_TREE_HPP_ +#define MERKLE_TREE_HPP_ + +#include +#include +#include "common/utils.hpp" + +namespace libsnark { + +/** + * A Merkle tree is maintained as two maps: + * - a map from addresses to values, and + * - a map from addresses to hashes. + * + * The second map maintains the intermediate hashes of a Merkle tree + * built atop the values currently stored in the tree (the + * implementation admits a very efficient support for sparse + * trees). Besides offering methods to load and store values, the + * class offers methods to retrieve the root of the Merkle tree and to + * obtain the authentication paths for (the value at) a given address. + */ + +typedef bit_vector merkle_authentication_node; +typedef std::vector merkle_authentication_path; + +template +class merkle_tree { +private: + + typedef typename HashT::hash_value_type hash_value_type; + typedef typename HashT::merkle_authentication_path_type merkle_authentication_path_type; + +public: + + std::vector hash_defaults; + std::map values; + std::map hashes; + + size_t depth; + size_t value_size; + size_t digest_size; + + merkle_tree(const size_t depth, const size_t value_size); + merkle_tree(const size_t depth, const size_t value_size, const std::vector &contents_as_vector); + merkle_tree(const size_t depth, const size_t value_size, const std::map &contents); + + bit_vector get_value(const size_t address) const; + void set_value(const size_t address, const bit_vector &value); + + hash_value_type get_root() const; + merkle_authentication_path_type get_path(const size_t address) const; + + void dump() const; +}; + +} // libsnark + +#include "common/data_structures/merkle_tree.tcc" + +#endif // MERKLE_TREE_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/common/data_structures/merkle_tree.tcc b/privacy/zsl/zsl/snark/libsnark/src/common/data_structures/merkle_tree.tcc new file mode 100644 index 0000000..281700b --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/common/data_structures/merkle_tree.tcc @@ -0,0 +1,246 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for Merkle tree. + + See merkle_tree.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef MERKLE_TREE_TCC +#define MERKLE_TREE_TCC + +#include + +#include "common/profiling.hpp" +#include "common/utils.hpp" + +namespace libsnark { + +template +typename HashT::hash_value_type two_to_one_CRH(const typename HashT::hash_value_type &l, + const typename HashT::hash_value_type &r) +{ + typename HashT::hash_value_type new_input; + new_input.insert(new_input.end(), l.begin(), l.end()); + new_input.insert(new_input.end(), r.begin(), r.end()); + + const size_t digest_size = HashT::get_digest_len(); + assert(l.size() == digest_size); + assert(r.size() == digest_size); + + return HashT::get_hash(new_input); +} + +template +merkle_tree::merkle_tree(const size_t depth, const size_t value_size) : + depth(depth), value_size(value_size) +{ + assert(depth < sizeof(size_t) * 8); + + digest_size = HashT::get_digest_len(); + assert(value_size <= digest_size); + + hash_value_type last(digest_size); + hash_defaults.reserve(depth+1); + hash_defaults.emplace_back(last); + for (size_t i = 0; i < depth; ++i) + { + last = two_to_one_CRH(last, last); + hash_defaults.emplace_back(last); + } + + std::reverse(hash_defaults.begin(), hash_defaults.end()); +} + +template +merkle_tree::merkle_tree(const size_t depth, + const size_t value_size, + const std::vector &contents_as_vector) : + merkle_tree(depth, value_size) +{ + assert(log2(contents_as_vector.size()) <= depth); + for (size_t address = 0; address < contents_as_vector.size(); ++address) + { + const size_t idx = address + (1ul< 0; --layer) + { + for (size_t idx = idx_begin; idx < idx_end; idx += 2) + { + hash_value_type l = hashes[idx]; // this is sound, because idx_begin is always a left child + hash_value_type r = (idx + 1 < idx_end ? hashes[idx+1] : hash_defaults[layer]); + + hash_value_type h = two_to_one_CRH(l, r); + hashes[(idx-1)/2] = h; + } + + idx_begin = (idx_begin-1)/2; + idx_end = (idx_end-1)/2; + } +} + +template +merkle_tree::merkle_tree(const size_t depth, + const size_t value_size, + const std::map &contents) : + merkle_tree(depth, value_size) +{ + + if (!contents.empty()) + { + assert(contents.rbegin()->first < 1ul<first; + const bit_vector value = it->second; + const size_t idx = address + (1ul< 0; --layer) + { + auto next_last_it = hashes.begin(); + + for (auto it = hashes.begin(); it != last_it; ++it) + { + const size_t idx = it->first; + const hash_value_type hash = it->second; + + if (idx % 2 == 0) + { + // this is the right child of its parent and by invariant we are missing the left child + hashes[(idx-1)/2] = two_to_one_CRH(hash_defaults[layer], hash); + } + else + { + if (std::next(it) == last_it || std::next(it)->first != idx + 1) + { + // this is the left child of its parent and is missing its right child + hashes[(idx-1)/2] = two_to_one_CRH(hash, hash_defaults[layer]); + } + else + { + // typical case: this is the left child of the parent and adjecent to it there is a right child + hashes[(idx-1)/2] = two_to_one_CRH(hash, std::next(it)->second); + ++it; + } + } + } + + last_it = next_last_it; + } + } +} + +template +bit_vector merkle_tree::get_value(const size_t address) const +{ + assert(log2(address) <= depth); + + auto it = values.find(address); + bit_vector padded_result = (it == values.end() ? bit_vector(digest_size) : it->second); + padded_result.resize(value_size); + + return padded_result; +} + +template +void merkle_tree::set_value(const size_t address, + const bit_vector &value) +{ + assert(log2(address) <= depth); + size_t idx = address + (1ul<=0; --layer) + { + idx = (idx-1)/2; + + auto it = hashes.find(2*idx+1); + hash_value_type l = (it == hashes.end() ? hash_defaults[layer+1] : it->second); + + it = hashes.find(2*idx+2); + hash_value_type r = (it == hashes.end() ? hash_defaults[layer+1] : it->second); + + hash_value_type h = two_to_one_CRH(l, r); + hashes[idx] = h; + } +} + +template +typename HashT::hash_value_type merkle_tree::get_root() const +{ + auto it = hashes.find(0); + return (it == hashes.end() ? hash_defaults[0] : it->second); +} + +template +typename HashT::merkle_authentication_path_type merkle_tree::get_path(const size_t address) const +{ + typename HashT::merkle_authentication_path_type result(depth); + assert(log2(address) <= depth); + size_t idx = address + (1ul< 0; --layer) + { + size_t sibling_idx = ((idx + 1) ^ 1) - 1; + auto it = hashes.find(sibling_idx); + if (layer == depth) + { + auto it2 = values.find(sibling_idx - ((1ul<second); + result[layer-1].resize(digest_size); + } + else + { + result[layer-1] = (it == hashes.end() ? hash_defaults[layer] : it->second); + } + + idx = (idx-1)/2; + } + + return result; +} + +template +void merkle_tree::dump() const +{ + for (size_t i = 0; i < 1ul< ", i); + const bit_vector value = (it == values.end() ? bit_vector(value_size) : it->second); + for (bool b : value) + { + printf("%d", b ? 1 : 0); + } + printf("\n"); + } + printf("\n"); +} + +} // libsnark + +#endif // MERKLE_TREE_TCC diff --git a/privacy/zsl/zsl/snark/libsnark/src/common/data_structures/set_commitment.cpp b/privacy/zsl/zsl/snark/libsnark/src/common/data_structures/set_commitment.cpp new file mode 100644 index 0000000..07e3e1e --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/common/data_structures/set_commitment.cpp @@ -0,0 +1,60 @@ +/** + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include "common/data_structures/set_commitment.hpp" +#include "common/serialization.hpp" + +namespace libsnark { + +bool set_membership_proof::operator==(const set_membership_proof &other) const +{ + return (this->address == other.address && + this->merkle_path == other.merkle_path); +} + +size_t set_membership_proof::size_in_bits() const +{ + if (merkle_path.empty()) + { + return (8 * sizeof(address)); + } + else + { + return (8 * sizeof(address) + merkle_path[0].size() * merkle_path.size()); + } +} + +std::ostream& operator<<(std::ostream &out, const set_membership_proof &proof) +{ + out << proof.address << "\n"; + out << proof.merkle_path.size() << "\n"; + for (size_t i = 0; i < proof.merkle_path.size(); ++i) + { + output_bool_vector(out, proof.merkle_path[i]); + } + + return out; +} + +std::istream& operator>>(std::istream &in, set_membership_proof &proof) +{ + in >> proof.address; + consume_newline(in); + size_t tree_depth; + in >> tree_depth; + consume_newline(in); + proof.merkle_path.resize(tree_depth); + + for (size_t i = 0; i < tree_depth; ++i) + { + input_bool_vector(in, proof.merkle_path[i]); + } + + return in; +} + +} // libsnark diff --git a/privacy/zsl/zsl/snark/libsnark/src/common/data_structures/set_commitment.hpp b/privacy/zsl/zsl/snark/libsnark/src/common/data_structures/set_commitment.hpp new file mode 100644 index 0000000..c9c21f4 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/common/data_structures/set_commitment.hpp @@ -0,0 +1,60 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for a Merkle tree based set commitment scheme. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef SET_COMMITMENT_HPP_ +#define SET_COMMITMENT_HPP_ + +#include "common/utils.hpp" +#include "common/data_structures/merkle_tree.hpp" +#include "gadgetlib1/gadgets/hashes/hash_io.hpp" // TODO: the current structure is suboptimal + +namespace libsnark { + +typedef bit_vector set_commitment; + +struct set_membership_proof { + size_t address; + merkle_authentication_path merkle_path; + + bool operator==(const set_membership_proof &other) const; + size_t size_in_bits() const; + friend std::ostream& operator<<(std::ostream &out, const set_membership_proof &other); + friend std::istream& operator>>(std::istream &in, set_membership_proof &other); +}; + +template +class set_commitment_accumulator { +private: + std::shared_ptr > tree; + std::map hash_to_pos; +public: + + size_t depth; + size_t digest_size; + size_t value_size; + + set_commitment_accumulator(const size_t max_entries, const size_t value_size=0); + + void add(const bit_vector &value); + bool is_in_set(const bit_vector &value) const; + set_commitment get_commitment() const; + + set_membership_proof get_membership_proof(const bit_vector &value) const; +}; + +} // libsnark + +/* note that set_commitment has both .cpp, for implementation of + non-templatized code (methods of set_membership_proof) and .tcc + (implementation of set_commitment_accumulator */ +#include "common/data_structures/set_commitment.tcc" + +#endif // SET_COMMITMENT_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/common/data_structures/set_commitment.tcc b/privacy/zsl/zsl/snark/libsnark/src/common/data_structures/set_commitment.tcc new file mode 100644 index 0000000..756509e --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/common/data_structures/set_commitment.tcc @@ -0,0 +1,70 @@ +/** @file + ***************************************************************************** + + Implementation of a Merkle tree based set commitment scheme. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef SET_COMMITMENT_TCC_ +#define SET_COMMITMENT_TCC_ + +namespace libsnark { + +template +set_commitment_accumulator::set_commitment_accumulator(const size_t max_entries, const size_t value_size) : + value_size(value_size) +{ + depth = log2(max_entries); + digest_size = HashT::get_digest_len(); + + tree.reset(new merkle_tree(depth, digest_size)); +} + +template +void set_commitment_accumulator::add(const bit_vector &value) +{ + assert(value_size == 0 || value.size() == value_size); + const bit_vector hash = HashT::get_hash(value); + if (hash_to_pos.find(hash) == hash_to_pos.end()) + { + const size_t pos = hash_to_pos.size(); + tree->set_value(pos, hash); + hash_to_pos[hash] = pos; + } +} + +template +bool set_commitment_accumulator::is_in_set(const bit_vector &value) const +{ + assert(value_size == 0 || value.size() == value_size); + const bit_vector hash = HashT::get_hash(value); + return (hash_to_pos.find(hash) != hash_to_pos.end()); +} + +template +set_commitment set_commitment_accumulator::get_commitment() const +{ + return tree->get_root(); +} + +template +set_membership_proof set_commitment_accumulator::get_membership_proof(const bit_vector &value) const +{ + const bit_vector hash = HashT::get_hash(value); + auto it = hash_to_pos.find(hash); + assert(it != hash_to_pos.end()); + + set_membership_proof proof; + proof.address = it->second; + proof.merkle_path = tree->get_path(it->second); + + return proof; +} + +} // libsnark + +#endif // SET_COMMITMENT_TCC_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/common/data_structures/sparse_vector.hpp b/privacy/zsl/zsl/snark/libsnark/src/common/data_structures/sparse_vector.hpp new file mode 100644 index 0000000..552a8ae --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/common/data_structures/sparse_vector.hpp @@ -0,0 +1,79 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for a sparse vector. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef SPARSE_VECTOR_HPP_ +#define SPARSE_VECTOR_HPP_ + +#include + +namespace libsnark { + +template +struct sparse_vector; + +template +std::ostream& operator<<(std::ostream &out, const sparse_vector &v); + +template +std::istream& operator>>(std::istream &in, sparse_vector &v); + +/** + * A sparse vector is a list of indices along with corresponding values. + * The indices are selected from the set {0,1,...,domain_size-1}. + */ +template +struct sparse_vector { + + std::vector indices; + std::vector values; + size_t domain_size_; + + sparse_vector() = default; + sparse_vector(const sparse_vector &other) = default; + sparse_vector(sparse_vector &&other) = default; + sparse_vector(std::vector &&v); /* constructor from std::vector */ + + sparse_vector& operator=(const sparse_vector &other) = default; + sparse_vector& operator=(sparse_vector &&other) = default; + + T operator[](const size_t idx) const; + + bool operator==(const sparse_vector &other) const; + bool operator==(const std::vector &other) const; + + bool is_valid() const; + bool empty() const; + + size_t domain_size() const; // return domain_size_ + size_t size() const; // return the number of indices (representing the number of non-zero entries) + size_t size_in_bits() const; // return the number bits needed to store the sparse vector + + /* return a pair consisting of the accumulated value and the sparse vector of non-accumuated values */ + template + std::pair > accumulate(const typename std::vector::const_iterator &it_begin, + const typename std::vector::const_iterator &it_end, + const size_t offset) const; + + friend std::ostream& operator<< (std::ostream &out, const sparse_vector &v); + friend std::istream& operator>> (std::istream &in, sparse_vector &v); +}; + +template +std::ostream& operator<<(std::ostream& out, const sparse_vector &v); + +template +std::istream& operator>>(std::istream& in, sparse_vector &v); + +} // libsnark + +#include "common/data_structures/sparse_vector.tcc" + +#endif // SPARSE_VECTOR_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/common/data_structures/sparse_vector.tcc b/privacy/zsl/zsl/snark/libsnark/src/common/data_structures/sparse_vector.tcc new file mode 100644 index 0000000..cfc5d75 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/common/data_structures/sparse_vector.tcc @@ -0,0 +1,316 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for a sparse vector. + + See sparse_vector.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef SPARSE_VECTOR_TCC_ +#define SPARSE_VECTOR_TCC_ + +#include "algebra/scalar_multiplication/multiexp.hpp" + +#include + +namespace libsnark { + +template +sparse_vector::sparse_vector(std::vector &&v) : + values(std::move(v)), domain_size_(values.size()) +{ + indices.resize(domain_size_); + std::iota(indices.begin(), indices.end(), 0); +} + +template +T sparse_vector::operator[](const size_t idx) const +{ + auto it = std::lower_bound(indices.begin(), indices.end(), idx); + return (it != indices.end() && *it == idx) ? values[it - indices.begin()] : T(); +} + +template +bool sparse_vector::operator==(const sparse_vector &other) const +{ + if (this->domain_size_ != other.domain_size_) + { + return false; + } + + size_t this_pos = 0, other_pos = 0; + while (this_pos < this->indices.size() && other_pos < other.indices.size()) + { + if (this->indices[this_pos] == other.indices[other_pos]) + { + if (this->values[this_pos] != other.values[other_pos]) + { + return false; + } + ++this_pos; + ++other_pos; + } + else if (this->indices[this_pos] < other.indices[other_pos]) + { + if (!this->values[this_pos].is_zero()) + { + return false; + } + ++this_pos; + } + else + { + if (!other.values[other_pos].is_zero()) + { + return false; + } + ++other_pos; + } + } + + /* at least one of the vectors has been exhausted, so other must be empty */ + while (this_pos < this->indices.size()) + { + if (!this->values[this_pos].is_zero()) + { + return false; + } + ++this_pos; + } + + while (other_pos < other.indices.size()) + { + if (!other.values[other_pos].is_zero()) + { + return false; + } + ++other_pos; + } + + return true; +} + +template +bool sparse_vector::operator==(const std::vector &other) const +{ + if (this->domain_size_ < other.size()) + { + return false; + } + + size_t j = 0; + for (size_t i = 0; i < other.size(); ++i) + { + if (this->indices[j] == i) + { + if (this->values[j] != other[j]) + { + return false; + } + ++j; + } + else + { + if (!other[j].is_zero()) + { + return false; + } + } + } + + return true; +} + +template +bool sparse_vector::is_valid() const +{ + if (values.size() == indices.size() && values.size() <= domain_size_) + { + return false; + } + + for (size_t i = 0; i + 1 < indices.size(); ++i) + { + if (indices[i] >= indices[i+1]) + { + return false; + } + } + + if (!indices.empty() && indices[indices.size()-1] >= domain_size_) + { + return false; + } + + return true; +} + +template +bool sparse_vector::empty() const +{ + return indices.empty(); +} + +template +size_t sparse_vector::domain_size() const +{ + return domain_size_; +} + +template +size_t sparse_vector::size() const +{ + return indices.size(); +} + +template +size_t sparse_vector::size_in_bits() const +{ + return indices.size() * (sizeof(size_t) * 8 + T::size_in_bits()); +} + +template +template +std::pair > sparse_vector::accumulate(const typename std::vector::const_iterator &it_begin, + const typename std::vector::const_iterator &it_end, + const size_t offset) const +{ + // TODO: does not really belong here. + const size_t chunks = 1; + const bool use_multiexp = true; + + T accumulated_value = T::zero(); + sparse_vector resulting_vector; + resulting_vector.domain_size_ = domain_size_; + + const size_t range_len = it_end - it_begin; + bool in_block = false; + size_t first_pos = -1, last_pos = -1; // g++ -flto emits unitialized warning, even though in_block guards for such cases. + + for (size_t i = 0; i < indices.size(); ++i) + { + const bool matching_pos = (offset <= indices[i] && indices[i] < offset + range_len); + // printf("i = %zu, pos[i] = %zu, offset = %zu, w_size = %zu\n", i, indices[i], offset, w_size); + bool copy_over; + + if (in_block) + { + if (matching_pos && last_pos == i-1) + { + // block can be extended, do it + last_pos = i; + copy_over = false; + } + else + { + // block has ended here + in_block = false; + copy_over = true; + +#ifdef DEBUG + print_indent(); printf("doing multiexp for w_%zu ... w_%zu\n", indices[first_pos], indices[last_pos]); +#endif + accumulated_value = accumulated_value + multi_exp(values.begin() + first_pos, + values.begin() + last_pos + 1, + it_begin + (indices[first_pos] - offset), + it_begin + (indices[last_pos] - offset) + 1, + chunks, use_multiexp); + } + } + else + { + if (matching_pos) + { + // block can be started + first_pos = i; + last_pos = i; + in_block = true; + copy_over = false; + } + else + { + copy_over = true; + } + } + + if (copy_over) + { + resulting_vector.indices.emplace_back(indices[i]); + resulting_vector.values.emplace_back(values[i]); + } + } + + if (in_block) + { +#ifdef DEBUG + print_indent(); printf("doing multiexp for w_%zu ... w_%zu\n", indices[first_pos], indices[last_pos]); +#endif + accumulated_value = accumulated_value + multi_exp(values.begin() + first_pos, + values.begin() + last_pos + 1, + it_begin + (indices[first_pos] - offset), + it_begin + (indices[last_pos] - offset) + 1, + chunks, use_multiexp); + } + + return std::make_pair(accumulated_value, resulting_vector); +} + +template +std::ostream& operator<<(std::ostream& out, const sparse_vector &v) +{ + out << v.domain_size_ << "\n"; + out << v.indices.size() << "\n"; + for (const size_t& i : v.indices) + { + out << i << "\n"; + } + + out << v.values.size() << "\n"; + for (const T& t : v.values) + { + out << t << OUTPUT_NEWLINE; + } + + return out; +} + +template +std::istream& operator>>(std::istream& in, sparse_vector &v) +{ + in >> v.domain_size_; + consume_newline(in); + + size_t s; + in >> s; + consume_newline(in); + v.indices.resize(s); + for (size_t i = 0; i < s; ++i) + { + in >> v.indices[i]; + consume_newline(in); + } + + v.values.clear(); + in >> s; + consume_newline(in); + v.values.reserve(s); + + for (size_t i = 0; i < s; ++i) + { + T t; + in >> t; + consume_OUTPUT_NEWLINE(in); + v.values.emplace_back(t); + } + + return in; +} + +} // libsnark + +#endif // SPARSE_VECTOR_TCC_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/common/default_types/bacs_ppzksnark_pp.hpp b/privacy/zsl/zsl/snark/libsnark/src/common/default_types/bacs_ppzksnark_pp.hpp new file mode 100644 index 0000000..c393b28 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/common/default_types/bacs_ppzksnark_pp.hpp @@ -0,0 +1,23 @@ + +/** @file + ***************************************************************************** + + This file defines default_bacs_ppzksnark_pp based on the elliptic curve + choice selected in ec_pp.hpp. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef BACS_PPZKSNARK_PP_HPP_ +#define BACS_PPZKSNARK_PP_HPP_ + +#include "common/default_types/ec_pp.hpp" + +namespace libsnark { +typedef default_ec_pp default_bacs_ppzksnark_pp; +} // libsnark + +#endif // BACS_PPZKSNARK_PP_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/common/default_types/ec_pp.hpp b/privacy/zsl/zsl/snark/libsnark/src/common/default_types/ec_pp.hpp new file mode 100644 index 0000000..b08c2da --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/common/default_types/ec_pp.hpp @@ -0,0 +1,53 @@ +/** @file + ***************************************************************************** + + This file defines default_ec_pp based on the CURVE=... make flag, which selects + which elliptic curve is used to implement group arithmetic and pairings. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef EC_PP_HPP_ +#define EC_PP_HPP_ + +/************************ Pick the elliptic curve ****************************/ + +#ifdef CURVE_ALT_BN128 +#include "algebra/curves/alt_bn128/alt_bn128_pp.hpp" +namespace libsnark { +typedef alt_bn128_pp default_ec_pp; +} // libsnark +#endif + +#ifdef CURVE_BN128 +#include "algebra/curves/bn128/bn128_pp.hpp" +namespace libsnark { +typedef bn128_pp default_ec_pp; +} // libsnark +#endif + +#ifdef CURVE_EDWARDS +#include "algebra/curves/edwards/edwards_pp.hpp" +namespace libsnark { +typedef edwards_pp default_ec_pp; +} // libsnark +#endif + +#ifdef CURVE_MNT4 +#include "algebra/curves/mnt/mnt4/mnt4_pp.hpp" +namespace libsnark { +typedef mnt4_pp default_ec_pp; +} // libsnark +#endif + +#ifdef CURVE_MNT6 +#include "algebra/curves/mnt/mnt6/mnt6_pp.hpp" +namespace libsnark { +typedef mnt6_pp default_ec_pp; +} // libsnark +#endif + +#endif // EC_PP_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/common/default_types/r1cs_gg_ppzksnark_pp.hpp b/privacy/zsl/zsl/snark/libsnark/src/common/default_types/r1cs_gg_ppzksnark_pp.hpp new file mode 100644 index 0000000..72cb704 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/common/default_types/r1cs_gg_ppzksnark_pp.hpp @@ -0,0 +1,22 @@ +/** @file + ***************************************************************************** + + This file defines default_r1cs_gg_ppzksnark_pp based on the elliptic curve + choice selected in ec_pp.hpp. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef R1CS_GG_PPZKSNARK_PP_HPP_ +#define R1CS_GG_PPZKSNARK_PP_HPP_ + +#include "common/default_types/ec_pp.hpp" + +namespace libsnark { +typedef default_ec_pp default_r1cs_gg_ppzksnark_pp; +} // libsnark + +#endif // R1CS_GG_PPZKSNARK_PP_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/common/default_types/r1cs_ppzkadsnark_pp.cpp b/privacy/zsl/zsl/snark/libsnark/src/common/default_types/r1cs_ppzkadsnark_pp.cpp new file mode 100644 index 0000000..aab2efe --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/common/default_types/r1cs_ppzkadsnark_pp.cpp @@ -0,0 +1,21 @@ +/** @file + ***************************************************************************** + + This file provides the initialization methods for the default ADSNARK params. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include "common/default_types/r1cs_ppzkadsnark_pp.hpp" + +namespace libsnark { + +void default_r1cs_ppzkadsnark_pp::init_public_params() +{ + snark_pp::init_public_params(); +} + +} // libsnark diff --git a/privacy/zsl/zsl/snark/libsnark/src/common/default_types/r1cs_ppzkadsnark_pp.hpp b/privacy/zsl/zsl/snark/libsnark/src/common/default_types/r1cs_ppzkadsnark_pp.hpp new file mode 100644 index 0000000..b35d3d7 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/common/default_types/r1cs_ppzkadsnark_pp.hpp @@ -0,0 +1,35 @@ +/** @file + ***************************************************************************** + + This file defines default_r1cs_ppzkadsnark_pp based on the elliptic curve + choice selected in ec_pp.hpp. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef R1CS_PPZKADSNARK_PP_HPP_ +#define R1CS_PPZKADSNARK_PP_HPP_ + +#include "common/default_types/r1cs_ppzksnark_pp.hpp" +#include "zk_proof_systems/ppzkadsnark/r1cs_ppzkadsnark/examples/prf/aes_ctr_prf.hpp" +#include "zk_proof_systems/ppzkadsnark/r1cs_ppzkadsnark/examples/signature/ed25519_signature.hpp" + +namespace libsnark { + + class default_r1cs_ppzkadsnark_pp { + public: + typedef default_r1cs_ppzksnark_pp snark_pp; + typedef ed25519_skT skT; + typedef ed25519_vkT vkT; + typedef ed25519_sigT sigT; + typedef aesPrfKeyT prfKeyT; + + static void init_public_params(); + }; + +}; // libsnark + +#endif // R1CS_PPZKADSNARK_PP_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/common/default_types/r1cs_ppzkpcd_pp.cpp b/privacy/zsl/zsl/snark/libsnark/src/common/default_types/r1cs_ppzkpcd_pp.cpp new file mode 100644 index 0000000..9281f5a --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/common/default_types/r1cs_ppzkpcd_pp.cpp @@ -0,0 +1,22 @@ +/** @file + ***************************************************************************** + + This file provides the initialization methods for the default PCD cycle. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include "common/default_types/r1cs_ppzkpcd_pp.hpp" + +namespace libsnark { + +void default_r1cs_ppzkpcd_pp::init_public_params() +{ + curve_A_pp::init_public_params(); + curve_B_pp::init_public_params(); +} + +} // libsnark diff --git a/privacy/zsl/zsl/snark/libsnark/src/common/default_types/r1cs_ppzkpcd_pp.hpp b/privacy/zsl/zsl/snark/libsnark/src/common/default_types/r1cs_ppzkpcd_pp.hpp new file mode 100644 index 0000000..f8d3fd0 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/common/default_types/r1cs_ppzkpcd_pp.hpp @@ -0,0 +1,35 @@ +/** @file + ***************************************************************************** + + This file defines the default PCD cycle. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef R1CS_PPZKPCD_PP_HPP_ +#define R1CS_PPZKPCD_PP_HPP_ + +/*********************** Define default PCD cycle ***************************/ + +#include "algebra/curves/mnt/mnt4/mnt4_pp.hpp" +#include "algebra/curves/mnt/mnt6/mnt6_pp.hpp" + +namespace libsnark { + +class default_r1cs_ppzkpcd_pp { +public: + typedef mnt4_pp curve_A_pp; + typedef mnt6_pp curve_B_pp; + + typedef Fr scalar_field_A; + typedef Fr scalar_field_B; + + static void init_public_params(); +}; + +} // libsnark + +#endif // R1CS_PPZKPCD_PP_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/common/default_types/r1cs_ppzksnark_pp.hpp b/privacy/zsl/zsl/snark/libsnark/src/common/default_types/r1cs_ppzksnark_pp.hpp new file mode 100644 index 0000000..c819b4a --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/common/default_types/r1cs_ppzksnark_pp.hpp @@ -0,0 +1,22 @@ +/** @file + ***************************************************************************** + + This file defines default_r1cs_ppzksnark_pp based on the elliptic curve + choice selected in ec_pp.hpp. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef R1CS_PPZKSNARK_PP_HPP_ +#define R1CS_PPZKSNARK_PP_HPP_ + +#include "common/default_types/ec_pp.hpp" + +namespace libsnark { +typedef default_ec_pp default_r1cs_ppzksnark_pp; +} // libsnark + +#endif // R1CS_PPZKSNARK_PP_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/common/default_types/ram_ppzksnark_pp.hpp b/privacy/zsl/zsl/snark/libsnark/src/common/default_types/ram_ppzksnark_pp.hpp new file mode 100644 index 0000000..2e7c15b --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/common/default_types/ram_ppzksnark_pp.hpp @@ -0,0 +1,24 @@ +/** @file + ***************************************************************************** + + This file defines the default architecture and curve choices for RAM + ppzk-SNARK. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef RAM_PPZKSNARK_PP_HPP_ +#define RAM_PPZKSNARK_PP_HPP_ + +#include "common/default_types/tinyram_ppzksnark_pp.hpp" + +namespace libsnark { + +typedef default_tinyram_ppzksnark_pp default_ram_ppzksnark_pp; + +} // libsnark + +#endif // RAM_PPZKSNARK_PP_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/common/default_types/ram_zksnark_pp.hpp b/privacy/zsl/zsl/snark/libsnark/src/common/default_types/ram_zksnark_pp.hpp new file mode 100644 index 0000000..806b978 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/common/default_types/ram_zksnark_pp.hpp @@ -0,0 +1,24 @@ +/** @file + ***************************************************************************** + + This file defines the default architecture and curve choices for RAM + zk-SNARK. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef RAM_ZKSNARK_PP_HPP_ +#define RAM_ZKSNARK_PP_HPP_ + +#include "common/default_types/tinyram_zksnark_pp.hpp" + +namespace libsnark { + +typedef default_tinyram_zksnark_pp default_ram_zksnark_pp; + +} // libsnark + +#endif // RAM_ZKSNARK_PP_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/common/default_types/tbcs_ppzksnark_pp.hpp b/privacy/zsl/zsl/snark/libsnark/src/common/default_types/tbcs_ppzksnark_pp.hpp new file mode 100644 index 0000000..f7ac0d1 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/common/default_types/tbcs_ppzksnark_pp.hpp @@ -0,0 +1,23 @@ + +/** @file + ***************************************************************************** + + This file defines default_tbcs_ppzksnark_pp based on the elliptic curve + choice selected in ec_pp.hpp. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef TBCS_PPZKSNARK_PP_HPP_ +#define TBCS_PPZKSNARK_PP_HPP_ + +#include "common/default_types/ec_pp.hpp" + +namespace libsnark { +typedef default_ec_pp default_tbcs_ppzksnark_pp; +} // libsnark + +#endif // TBCS_PPZKSNARK_PP_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/common/default_types/tinyram_ppzksnark_pp.cpp b/privacy/zsl/zsl/snark/libsnark/src/common/default_types/tinyram_ppzksnark_pp.cpp new file mode 100644 index 0000000..5daba1a --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/common/default_types/tinyram_ppzksnark_pp.cpp @@ -0,0 +1,21 @@ +/** @file + ***************************************************************************** + + This file provides the initialization methods for the default TinyRAM ppzk-SNARK. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include "common/default_types/tinyram_ppzksnark_pp.hpp" + +namespace libsnark { + +void default_tinyram_ppzksnark_pp::init_public_params() +{ + snark_pp::init_public_params(); +} + +} // libsnark diff --git a/privacy/zsl/zsl/snark/libsnark/src/common/default_types/tinyram_ppzksnark_pp.hpp b/privacy/zsl/zsl/snark/libsnark/src/common/default_types/tinyram_ppzksnark_pp.hpp new file mode 100644 index 0000000..7953d4f --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/common/default_types/tinyram_ppzksnark_pp.hpp @@ -0,0 +1,32 @@ +/** @file + ***************************************************************************** + + This file defines the default architecture and curve choices for RAM + ppzk-SNARK. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef TINYRAM_PPZKSNARK_PP_HPP_ +#define TINYRAM_PPZKSNARK_PP_HPP_ + +#include "common/default_types/r1cs_ppzksnark_pp.hpp" +#include "relations/ram_computations/rams/tinyram/tinyram_params.hpp" + +namespace libsnark { + +class default_tinyram_ppzksnark_pp { +public: + typedef default_r1cs_ppzksnark_pp snark_pp; + typedef Fr FieldT; + typedef ram_tinyram machine_pp; + + static void init_public_params(); +}; + +} // libsnark + +#endif // TINYRAM_PPZKSNARK_PP_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/common/default_types/tinyram_zksnark_pp.cpp b/privacy/zsl/zsl/snark/libsnark/src/common/default_types/tinyram_zksnark_pp.cpp new file mode 100644 index 0000000..2373833 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/common/default_types/tinyram_zksnark_pp.cpp @@ -0,0 +1,21 @@ +/** @file + ***************************************************************************** + + This file provides the initialization methods for the default TinyRAM zk-SNARK. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include "common/default_types/tinyram_zksnark_pp.hpp" + +namespace libsnark { + +void default_tinyram_zksnark_pp::init_public_params() +{ + PCD_pp::init_public_params(); +} + +} // libsnark diff --git a/privacy/zsl/zsl/snark/libsnark/src/common/default_types/tinyram_zksnark_pp.hpp b/privacy/zsl/zsl/snark/libsnark/src/common/default_types/tinyram_zksnark_pp.hpp new file mode 100644 index 0000000..e382472 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/common/default_types/tinyram_zksnark_pp.hpp @@ -0,0 +1,31 @@ +/** @file + ***************************************************************************** + + This file defines the default choices of TinyRAM zk-SNARK. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef TINYRAM_PPZKSNARK_PP_HPP_ +#define TINYRAM_PPZKSNARK_PP_HPP_ + +#include "common/default_types/r1cs_ppzkpcd_pp.hpp" +#include "relations/ram_computations/rams/tinyram/tinyram_params.hpp" + +namespace libsnark { + +class default_tinyram_zksnark_pp { +public: + typedef default_r1cs_ppzkpcd_pp PCD_pp; + typedef typename PCD_pp::scalar_field_A FieldT; + typedef ram_tinyram machine_pp; + + static void init_public_params(); +}; + +} // libsnark + +#endif // TINYRAM_PPZKSNARK_PP_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/common/default_types/uscs_ppzksnark_pp.hpp b/privacy/zsl/zsl/snark/libsnark/src/common/default_types/uscs_ppzksnark_pp.hpp new file mode 100644 index 0000000..59d1917 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/common/default_types/uscs_ppzksnark_pp.hpp @@ -0,0 +1,23 @@ + +/** @file + ***************************************************************************** + + This file defines default_uscs_ppzksnark_pp based on the elliptic curve + choice selected in ec_pp.hpp. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef USCS_PPZKSNARK_PP_HPP_ +#define USCS_PPZKSNARK_PP_HPP_ + +#include "common/default_types/ec_pp.hpp" + +namespace libsnark { +typedef default_ec_pp default_uscs_ppzksnark_pp; +} // libsnark + +#endif // USCS_PPZKSNARK_PP_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/common/profiling.cpp b/privacy/zsl/zsl/snark/libsnark/src/common/profiling.cpp new file mode 100644 index 0000000..3aca302 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/common/profiling.cpp @@ -0,0 +1,379 @@ +/** @file + ***************************************************************************** + + Implementation of functions for profiling code blocks. + + See profiling.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include "common/profiling.hpp" +#include +#include +#include +#include +#include +#include +#include +#include "common/default_types/ec_pp.hpp" +#include "common/utils.hpp" + +#ifndef NO_PROCPS +#include +#endif + +namespace libsnark { + +long long get_nsec_time() +{ + auto timepoint = std::chrono::high_resolution_clock::now(); + return std::chrono::duration_cast(timepoint.time_since_epoch()).count(); +} + +/* Return total CPU time consumsed by all threads of the process, in nanoseconds. */ +long long get_nsec_cpu_time() +{ + ::timespec ts; + if ( ::clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts) ) + throw ::std::runtime_error("clock_gettime(CLOCK_PROCESS_CPUTIME_ID) failed"); + // If we expected this to work, don't silently ignore failures, because that would hide the problem and incur an unnecessarily system-call overhead. So if we ever observe this exception, we should probably add a suitable #ifdef . + //TODO: clock_gettime(CLOCK_PROCESS_CPUTIME_ID) is not supported by native Windows. What about Cygwin? Should we #ifdef on CLOCK_PROCESS_CPUTIME_ID or on __linux__? + return ts.tv_sec * 1000000000ll + ts.tv_nsec; +} + +long long start_time, last_time; +long long start_cpu_time, last_cpu_time; + +void start_profiling() +{ + printf("Reset time counters for profiling\n"); + + last_time = start_time = get_nsec_time(); + last_cpu_time = start_cpu_time = get_nsec_cpu_time(); +} + +std::map invocation_counts; +std::map enter_times; +std::map last_times; +std::map cumulative_times; +//TODO: Instead of analogous maps for time and cpu_time, use a single struct-valued map +std::map enter_cpu_times; +std::map last_cpu_times; +std::map, long long> op_counts; +std::map, long long> cumulative_op_counts; // ((msg, data_point), value) + // TODO: Convert op_counts and cumulative_op_counts from pair to structs +size_t indentation = 0; + +std::vector block_names; + +std::list > op_data_points = { +#ifdef PROFILE_OP_COUNTS + std::make_pair("Fradd", &Fr::add_cnt), + std::make_pair("Frsub", &Fr::sub_cnt), + std::make_pair("Frmul", &Fr::mul_cnt), + std::make_pair("Frinv", &Fr::inv_cnt), + std::make_pair("Fqadd", &Fq::add_cnt), + std::make_pair("Fqsub", &Fq::sub_cnt), + std::make_pair("Fqmul", &Fq::mul_cnt), + std::make_pair("Fqinv", &Fq::inv_cnt), + std::make_pair("G1add", &G1::add_cnt), + std::make_pair("G1dbl", &G1::dbl_cnt), + std::make_pair("G2add", &G2::add_cnt), + std::make_pair("G2dbl", &G2::dbl_cnt) +#endif +}; + +bool inhibit_profiling_info = false; +bool inhibit_profiling_counters = false; + +void clear_profiling_counters() +{ + invocation_counts.clear(); + last_times.clear(); + last_cpu_times.clear(); + cumulative_times.clear(); +} + +void print_cumulative_time_entry(const std::string &key, const long long factor) +{ + const double total_ms = (cumulative_times.at(key) * 1e-6); + const size_t cnt = invocation_counts.at(key); + const double avg_ms = total_ms / cnt; + printf(" %-45s: %12.5fms = %lld * %0.5fms (%zu invocations, %0.5fms = %lld * %0.5fms per invocation)\n", key.c_str(), total_ms, factor, total_ms/factor, cnt, avg_ms, factor, avg_ms/factor); +} + +void print_cumulative_times(const long long factor) +{ + printf("Dumping times:\n"); + for (auto& kv : cumulative_times) + { + print_cumulative_time_entry(kv.first, factor); + } +} + +void print_cumulative_op_counts(const bool only_fq) +{ +#ifdef PROFILE_OP_COUNTS + printf("Dumping operation counts:\n"); + for (auto& msg : invocation_counts) + { + printf(" %-45s: ", msg.first.c_str()); + bool first = true; + for (auto& data_point : op_data_points) + { + if (only_fq && data_point.first.compare(0, 2, "Fq") != 0) + { + continue; + } + + if (!first) + { + printf(", "); + } + printf("%-5s = %7.0f (%3zu)", + data_point.first.c_str(), + 1. * cumulative_op_counts[std::make_pair(msg.first, data_point.first)] / msg.second, + msg.second); + first = false; + } + printf("\n"); + } +#else + UNUSED(only_fq); +#endif +} + +void print_op_profiling(const std::string &msg) +{ +#ifdef PROFILE_OP_COUNTS + printf("\n"); + print_indent(); + + printf("(opcounts) = ("); + bool first = true; + for (std::pair p : op_data_points) + { + if (!first) + { + printf(", "); + } + + printf("%s=%lld", p.first.c_str(), *(p.second)-op_counts[std::make_pair(msg, p.first)]); + first = false; + } + printf(")"); +#else + UNUSED(msg); +#endif +} + +static void print_times_from_last_and_start(long long now, long long last, + long long cpu_now, long long cpu_last) +{ + long long time_from_start = now - start_time; + long long time_from_last = now - last; + + long long cpu_time_from_start = cpu_now - start_cpu_time; + long long cpu_time_from_last = cpu_now - cpu_last; + + if (time_from_last != 0) { + double parallelism_from_last = 1.0 * cpu_time_from_last / time_from_last; + printf("[%0.4fs x%0.2f]", time_from_last * 1e-9, parallelism_from_last); + } else { + printf("[ ]"); + } + if (time_from_start != 0) { + double parallelism_from_start = 1.0 * cpu_time_from_start / time_from_start; + printf("\t(%0.4fs x%0.2f from start)", time_from_start * 1e-9, parallelism_from_start); + } +} + +void print_time(const char* msg) +{ + if (inhibit_profiling_info) + { + return; + } + + long long now = get_nsec_time(); + long long cpu_now = get_nsec_cpu_time(); + + printf("%-35s\t", msg); + print_times_from_last_and_start(now, last_time, cpu_now, last_cpu_time); +#ifdef PROFILE_OP_COUNTS + print_op_profiling(msg); +#endif + printf("\n"); + + fflush(stdout); + last_time = now; + last_cpu_time = cpu_now; +} + +void print_header(const char *msg) +{ + printf("\n================================================================================\n"); + printf("%s\n", msg); + printf("================================================================================\n\n"); +} + +void print_indent() +{ + for (size_t i = 0; i < indentation; ++i) + { + printf(" "); + } +} + +void op_profiling_enter(const std::string &msg) +{ + for (std::pair p : op_data_points) + { + op_counts[std::make_pair(msg, p.first)] = *(p.second); + } +} + +void enter_block(const std::string &msg, const bool indent) +{ + if (inhibit_profiling_counters) + { + return; + } + + block_names.emplace_back(msg); + long long t = get_nsec_time(); + enter_times[msg] = t; + long long cpu_t = get_nsec_cpu_time(); + enter_cpu_times[msg] = cpu_t; + + if (inhibit_profiling_info) + { + return; + } + +#ifdef MULTICORE +#pragma omp critical +#endif + { + op_profiling_enter(msg); + + print_indent(); + printf("(enter) %-35s\t", msg.c_str()); + print_times_from_last_and_start(t, t, cpu_t, cpu_t); + printf("\n"); + fflush(stdout); + + if (indent) + { + ++indentation; + } + } +} + +void leave_block(const std::string &msg, const bool indent) +{ + if (inhibit_profiling_counters) + { + return; + } + +#ifndef MULTICORE + assert(*(--block_names.end()) == msg); +#endif + block_names.pop_back(); + + ++invocation_counts[msg]; + + long long t = get_nsec_time(); + last_times[msg] = (t - enter_times[msg]); + cumulative_times[msg] += (t - enter_times[msg]); + + long long cpu_t = get_nsec_cpu_time(); + last_cpu_times[msg] = (cpu_t - enter_cpu_times[msg]); + +#ifdef PROFILE_OP_COUNTS + for (std::pair p : op_data_points) + { + cumulative_op_counts[std::make_pair(msg, p.first)] += *(p.second)-op_counts[std::make_pair(msg, p.first)]; + } +#endif + + if (inhibit_profiling_info) + { + return; + } + +#ifdef MULTICORE +#pragma omp critical +#endif + { + if (indent) + { + --indentation; + } + + print_indent(); + printf("(leave) %-35s\t", msg.c_str()); + print_times_from_last_and_start(t, enter_times[msg], cpu_t, enter_cpu_times[msg]); + print_op_profiling(msg); + printf("\n"); + fflush(stdout); + } +} + +void print_mem(const std::string &s) +{ +#ifndef NO_PROCPS + struct proc_t usage; + look_up_our_self(&usage); + if (s.empty()) + { + printf("* Peak vsize (physical memory+swap) in mebibytes: %lu\n", usage.vsize >> 20); + } + else + { + printf("* Peak vsize (physical memory+swap) in mebibytes (%s): %lu\n", s.c_str(), usage.vsize >> 20); + } +#else + printf("* Memory profiling not supported in NO_PROCPS mode\n"); +#endif +} + +void print_compilation_info() +{ +#ifdef __GNUC__ + printf("g++ version: %s\n", __VERSION__); + printf("Compiled on %s %s\n", __DATE__, __TIME__); +#endif +#ifdef STATIC + printf("STATIC: yes\n"); +#else + printf("STATIC: no\n"); +#endif +#ifdef MULTICORE + printf("MULTICORE: yes\n"); +#else + printf("MULTICORE: no\n"); +#endif +#ifdef DEBUG + printf("DEBUG: yes\n"); +#else + printf("DEBUG: no\n"); +#endif +#ifdef PROFILE_OP_COUNTS + printf("PROFILE_OP_COUNTS: yes\n"); +#else + printf("PROFILE_OP_COUNTS: no\n"); +#endif +#ifdef _GLIBCXX_DEBUG + printf("_GLIBCXX_DEBUG: yes\n"); +#else + printf("_GLIBCXX_DEBUG: no\n"); +#endif +} + +} // libsnark diff --git a/privacy/zsl/zsl/snark/libsnark/src/common/profiling.hpp b/privacy/zsl/zsl/snark/libsnark/src/common/profiling.hpp new file mode 100644 index 0000000..9619117 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/common/profiling.hpp @@ -0,0 +1,51 @@ +/** @file + ***************************************************************************** + + Declaration of functions for profiling code blocks. + + Reports time, operation counts, memory usage, and others. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef PROFILING_HPP_ +#define PROFILING_HPP_ + +#include +#include +#include +#include + +namespace libsnark { + +void start_profiling(); +long long get_nsec_time(); +void print_time(const char* msg); +void print_header(const char* msg); + +void print_indent(); + +extern bool inhibit_profiling_info; +extern bool inhibit_profiling_counters; +extern std::map invocation_counts; +extern std::map last_times; +extern std::map cumulative_times; + +void clear_profiling_counters(); + +void print_cumulative_time_entry(const std::string &key, const long long factor=1); +void print_cumulative_times(const long long factor=1); +void print_cumulative_op_counts(const bool only_fq=false); + +void enter_block(const std::string &msg, const bool indent=true); +void leave_block(const std::string &msg, const bool indent=true); + +void print_mem(const std::string &s = ""); +void print_compilation_info(); + +} // libsnark + +#endif // PROFILING_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/common/rng.hpp b/privacy/zsl/zsl/snark/libsnark/src/common/rng.hpp new file mode 100644 index 0000000..6d0896f --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/common/rng.hpp @@ -0,0 +1,26 @@ +/** @file + ***************************************************************************** + + Declaration of functions for generating randomness. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef RNG_HPP_ +#define RNG_HPP_ + +#include + +namespace libsnark { + +template +FieldT SHA512_rng(const uint64_t idx); + +} // libsnark + +#include "common/rng.tcc" + +#endif // RNG_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/common/rng.tcc b/privacy/zsl/zsl/snark/libsnark/src/common/rng.tcc new file mode 100644 index 0000000..44020da --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/common/rng.tcc @@ -0,0 +1,69 @@ +/** @file + ***************************************************************************** + + Implementation of functions for generating randomness. + + See rng.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef RNG_TCC_ +#define RNG_TCC_ + +#include + +namespace libsnark { + +template +FieldT SHA512_rng(const uint64_t idx) +{ + assert(GMP_NUMB_BITS == 64); // current Python code cannot handle larger values, so testing here for some assumptions. + assert(is_little_endian()); + + assert(FieldT::size_in_bits() <= SHA512_DIGEST_LENGTH * 8); + + bigint rval; + uint64_t iter = 0; + do + { + mp_limb_t hash[((SHA512_DIGEST_LENGTH*8) + GMP_NUMB_BITS - 1)/GMP_NUMB_BITS]; + + SHA512_CTX sha512; + SHA512_Init(&sha512); + SHA512_Update(&sha512, &idx, sizeof(idx)); + SHA512_Update(&sha512, &iter, sizeof(iter)); + SHA512_Final((unsigned char*)hash, &sha512); + + for (mp_size_t i = 0; i < FieldT::num_limbs; ++i) + { + rval.data[i] = hash[i]; + } + + /* clear all bits higher than MSB of modulus */ + size_t bitno = GMP_NUMB_BITS * FieldT::num_limbs; + while (FieldT::mod.test_bit(bitno) == false) + { + const std::size_t part = bitno/GMP_NUMB_BITS; + const std::size_t bit = bitno - (GMP_NUMB_BITS*part); + + rval.data[part] &= ~(1ul<= modulus -- repeat (rejection sampling) */ + while (mpn_cmp(rval.data, FieldT::mod.data, FieldT::num_limbs) >= 0); + + return FieldT(rval); +} + +} // libsnark + +#endif // RNG_TCC_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/common/routing_algorithms/as_waksman_routing_algorithm.cpp b/privacy/zsl/zsl/snark/libsnark/src/common/routing_algorithms/as_waksman_routing_algorithm.cpp new file mode 100644 index 0000000..3ff7985 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/common/routing_algorithms/as_waksman_routing_algorithm.cpp @@ -0,0 +1,549 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for functionality for routing on an arbitrary-size (AS) Waksman network. + + See as_waksman_routing_algorithm.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include + +#include "common/routing_algorithms/as_waksman_routing_algorithm.hpp" + +namespace libsnark { + +/** + * Return the height of the AS-Waksman network's top sub-network. + */ +size_t as_waksman_top_height(const size_t num_packets) +{ + return num_packets/2; +} + +/** + * Return the input wire of a left-hand side switch of an AS-Waksman network for + * a given number of packets. + * + * A switch is specified by a row index row_idx, relative to a "row_offset" that + * records the level of recursion. (The corresponding column index column_idx + * can be inferred from row_offset and num_packets, and it is easier to reason about + * implicitly.) + * + * If top = true, return the top wire, otherwise return bottom wire. + */ +size_t as_waksman_switch_output(const size_t num_packets, const size_t row_offset, const size_t row_idx, const bool use_top) +{ + size_t relpos = row_idx - row_offset; + assert(relpos % 2 == 0 && relpos + 1 < num_packets); + return row_offset + (relpos / 2) + (use_top ? 0 : as_waksman_top_height(num_packets)); +} + +/** + * Return the input wire of a right-hand side switch of an AS-Waksman network for + * a given number of packets. + * + * This function is analogous to as_waksman_switch_output above. + */ +size_t as_waksman_switch_input(const size_t num_packets, const size_t row_offset, const size_t row_idx, const bool use_top) +{ + /* Due to symmetry, this function equals as_waksman_switch_output. */ + return as_waksman_switch_output(num_packets, row_offset, row_idx, use_top); +} + +size_t as_waksman_num_columns(const size_t num_packets) +{ + return (num_packets > 1 ? 2*log2(num_packets)-1 : 0); +} + +/** + * Construct AS-Waksman subnetwork occupying switch columns + * [left,left+1, ..., right] + * that will route + * - from left-hand side inputs [lo,lo+1,...,hi] + * - to right-hand side destinations rhs_dests[0],rhs_dests[1],...,rhs_dests[hi-lo+1]. + * That is, rhs_dests are 0-indexed w.r.t. row_offset of lo. + * + * Note that rhs_dests is *not* a permutation of [lo, lo+1, ... hi]. + * + * This function fills out neighbors[left] and neighbors[right-1]. + */ +void construct_as_waksman_inner(const size_t left, + const size_t right, + const size_t lo, + const size_t hi, + const std::vector rhs_dests, + as_waksman_topology &neighbors) +{ + if (left > right) + { + return; + } + + const size_t subnetwork_size = (hi - lo + 1); + assert(rhs_dests.size() == subnetwork_size); + const size_t subnetwork_width = as_waksman_num_columns(subnetwork_size); + assert(right - left + 1 >= subnetwork_width); + + if (right - left + 1 > subnetwork_width) + { + /** + * If there is more space for the routing network than needed, + * just add straight edges. This also handles the size-1 base case. + */ + for (size_t packet_idx = lo; packet_idx <= hi; ++packet_idx) + { + neighbors[left][packet_idx].first = neighbors[left][packet_idx].second = packet_idx; + neighbors[right][packet_idx].first = neighbors[right][packet_idx].second = rhs_dests[packet_idx - lo]; + } + + std::vector new_rhs_dests(subnetwork_size, -1); + for (size_t packet_idx = lo; packet_idx <= hi; ++packet_idx) + { + new_rhs_dests[packet_idx-lo] = packet_idx; + } + + construct_as_waksman_inner(left+1, right-1, lo, hi, new_rhs_dests, neighbors); + } + else if (subnetwork_size == 2) + { + /* Non-trivial base case: routing a 2-element permutation. */ + neighbors[left][lo].first = neighbors[left][hi].second = rhs_dests[0]; + neighbors[left][lo].second = neighbors[left][hi].first = rhs_dests[1]; + } + else + { + /** + * Networks of size sz > 2 are handled by adding two columns of + * switches alongside the network and recursing. + */ + std::vector new_rhs_dests(subnetwork_size, -1); + + /** + * This adds floor(sz/2) switches alongside the network. + * + * As per the AS-Waksman construction, one of the switches in the + * even case can be eliminated (i.e., set to a constant). We handle + * this later. + */ + for (size_t row_idx = lo; row_idx < (subnetwork_size % 2 == 1 ? hi : hi + 1); row_idx += 2) + { + neighbors[left][row_idx].first = neighbors[left][row_idx+1].second = as_waksman_switch_output(subnetwork_size, lo, row_idx, true); + neighbors[left][row_idx].second = neighbors[left][row_idx+1].first = as_waksman_switch_output(subnetwork_size, lo, row_idx, false); + + new_rhs_dests[as_waksman_switch_input(subnetwork_size, lo, row_idx, true)-lo] = row_idx; + new_rhs_dests[as_waksman_switch_input(subnetwork_size, lo, row_idx, false)-lo] = row_idx + 1; + + neighbors[right][row_idx].first = neighbors[right][row_idx+1].second = rhs_dests[row_idx-lo]; + neighbors[right][row_idx].second = neighbors[right][row_idx+1].first = rhs_dests[row_idx+1-lo]; + } + + if (subnetwork_size % 2 == 1) + { + /** + * Odd special case: + * the last wire is not connected to any switch, + * and the the wire is mereley routed "straight". + */ + neighbors[left][hi].first = neighbors[left][hi].second = hi; + neighbors[right][hi].first = neighbors[right][hi].second = rhs_dests[hi-lo]; + new_rhs_dests[hi-lo] = hi; + } + else + { + /** + * Even special case: + * fix the bottom-most left-hand-side switch + * to a constant "straight" setting. + */ + neighbors[left][hi-1].second = neighbors[left][hi-1].first; + neighbors[left][hi].second = neighbors[left][hi].first; + } + + const size_t d = as_waksman_top_height(subnetwork_size); + const std::vector new_rhs_dests_top(new_rhs_dests.begin(), new_rhs_dests.begin()+d); + const std::vector new_rhs_dests_bottom(new_rhs_dests.begin()+d, new_rhs_dests.end()); + + construct_as_waksman_inner(left+1, right-1, lo, lo+d-1, new_rhs_dests_top, neighbors); + construct_as_waksman_inner(left+1, right-1, lo+d, hi, new_rhs_dests_bottom, neighbors); + } +} + +as_waksman_topology generate_as_waksman_topology(const size_t num_packets) +{ + assert(num_packets > 1); + const size_t width = as_waksman_num_columns(num_packets); + + as_waksman_topology neighbors(width, std::vector >(num_packets, std::make_pair(-1, -1))); + + std::vector rhs_dests(num_packets); + for (size_t packet_idx = 0; packet_idx < num_packets; ++packet_idx) + { + rhs_dests[packet_idx] = packet_idx; + } + + construct_as_waksman_inner(0, width-1, 0, num_packets-1, rhs_dests, neighbors); + + return neighbors; +} + +/** + * Given either a position occupied either by its top or bottom ports, + * return the row index of its canonical position. + * + * This function is agnostic to column_idx, given row_offset, so we omit + * column_idx. + */ +size_t as_waksman_get_canonical_row_idx(const size_t row_offset, const size_t row_idx) +{ + /* translate back relative to row_offset, clear LSB, and then translate forward */ + return (((row_idx - row_offset) & ~1) + row_offset); +} + +/** + * Return a switch value that makes switch row_idx = + * as_waksman_switch_position_from_wire_position(row_offset, packet_idx) to + * route the wire packet_idx via the top (if top = true), resp., + * bottom (if top = false) subnetwork. + * + * NOTE: pos is assumed to be + * - the input position for the LHS switches, and + * - the output position for the RHS switches. + */ +bool as_waksman_get_switch_setting_from_top_bottom_decision(const size_t row_offset, const size_t packet_idx, const bool use_top) +{ + const size_t row_idx = as_waksman_get_canonical_row_idx(row_offset, packet_idx); + return (packet_idx == row_idx) ^ use_top; +} + +/** + * Return true if the switch with input port at (column_idx, row_idx) + * when set to "straight" (if top = true), resp., "cross" (if top = + * false), routes the packet at (column_idx, row_idx) via the top + * subnetwork. + * + * NOTE: packet_idx is assumed to be + * - the input position for the RHS switches, and + * - the output position for the LHS switches. + */ +bool as_waksman_get_top_bottom_decision_from_switch_setting(const size_t row_offset, const size_t packet_idx, const bool switch_setting) +{ + const size_t row_idx = as_waksman_get_canonical_row_idx(row_offset, packet_idx); + return (row_idx == packet_idx) ^ switch_setting; +} + +/** + * Given an output wire of a RHS switch, compute and return the output + * position of the other wire also connected to this switch. + */ +size_t as_waksman_other_output_position(const size_t row_offset, const size_t packet_idx) +{ + const size_t row_idx = as_waksman_get_canonical_row_idx(row_offset, packet_idx); + return (1 - (packet_idx - row_idx)) + row_idx; +} + +/** + * Given an input wire of a LHS switch, compute and return the input + * position of the other wire also connected to this switch. + */ +size_t as_waksman_other_input_position(const size_t row_offset, const size_t packet_idx) +{ + /* Due to symmetry, this function equals as_waksman_other_output_position. */ + return as_waksman_other_output_position(row_offset, packet_idx); +} + +/** + * Compute AS-Waksman switch settings for the subnetwork occupying switch columns + * [left,left+1,...,right] + * that will route + * - from left-hand side inputs [lo,lo+1,...,hi] + * - to right-hand side destinations pi[lo],pi[lo+1],...,pi[hi]. + * + * The permutation + * - pi maps [lo, lo+1, ... hi] to itself, offset by lo, and + * - piinv is the inverse of pi. + * + * NOTE: due to offsets, neither pi or piinv are instances of integer_permutation. + */ +void as_waksman_route_inner(const size_t left, + const size_t right, + const size_t lo, + const size_t hi, + const integer_permutation &permutation, + const integer_permutation &permutation_inv, + as_waksman_routing &routing) +{ + if (left > right) + { + return; + } + + const size_t subnetwork_size = (hi - lo + 1); + const size_t subnetwork_width = as_waksman_num_columns(subnetwork_size); + assert(right - left + 1 >= subnetwork_width); + +#ifdef DEBUG + assert(permutation.min_element == lo); + assert(permutation.max_element == hi); + assert(permutation.size() == subnetwork_size); + assert(permutation.is_valid()); + assert(permutation.inverse() == permutation_inv); +#endif + + if (right - left + 1 > subnetwork_width) + { + /** + * If there is more space for the routing network than required, + * then the topology for this subnetwork includes straight edges + * along its sides and no switches, so it suffices to recurse. + */ + as_waksman_route_inner(left+1, right-1, lo, hi, permutation, permutation_inv, routing); + } + else if (subnetwork_size == 2) + { + /** + * Non-trivial base case: switch settings for a 2-element permutation + */ + assert(permutation.get(lo) == lo || permutation.get(lo) == lo+1); + assert(permutation.get(lo+1) == lo || permutation.get(lo+1) == lo + 1); + assert(permutation.get(lo) != permutation.get(lo+1)); + + routing[left][lo] = (permutation.get(lo) != lo); + } + else + { + /** + * The algorithm first assigns a setting to a LHS switch, + * route its target to RHS, which will enforce a RHS switch setting. + * Then, it back-routes the RHS value back to LHS. + * If this enforces a LHS switch setting, then forward-route that; + * otherwise we will select the next value from LHS to route. + */ + integer_permutation new_permutation(lo, hi); + integer_permutation new_permutation_inv(lo, hi); + std::vector lhs_routed(subnetwork_size, false); /* offset by lo, i.e. lhs_routed[packet_idx-lo] is set if packet packet_idx is routed */ + + size_t to_route; + size_t max_unrouted; + bool route_left; + + if (subnetwork_size % 2 == 1) + { + /** + * ODD CASE: we first deal with the bottom-most straight wire, + * which is not connected to any of the switches at this level + * of recursion and just passed into the lower subnetwork. + */ + if (permutation.get(hi) == hi) + { + /** + * Easy sub-case: it is routed directly to the bottom-most + * wire on RHS, so no switches need to be touched. + */ + new_permutation.set(hi, hi); + new_permutation_inv.set(hi, hi); + to_route = hi - 1; + route_left = true; + } + else + { + /** + * Other sub-case: the straight wire is routed to a switch + * on RHS, so route the other value from that switch + * using the lower subnetwork. + */ + const size_t rhs_switch = as_waksman_get_canonical_row_idx(lo, permutation.get(hi)); + const bool rhs_switch_setting = as_waksman_get_switch_setting_from_top_bottom_decision(lo, permutation.get(hi), false); + routing[right][rhs_switch] = rhs_switch_setting; + size_t tprime = as_waksman_switch_input(subnetwork_size, lo, rhs_switch, false); + new_permutation.set(hi, tprime); + new_permutation_inv.set(tprime, hi); + + to_route = as_waksman_other_output_position(lo, permutation.get(hi)); + route_left = false; + } + + lhs_routed[hi-lo] = true; + max_unrouted = hi - 1; + } + else + { + /** + * EVEN CASE: the bottom-most switch is fixed to a constant + * straight setting. So we route wire hi accordingly. + */ + routing[left][hi-1] = false; + to_route = hi; + route_left = true; + max_unrouted = hi; + } + + while (1) + { + /** + * INVARIANT: the wire `to_route' on LHS (if route_left = true), + * resp., RHS (if route_left = false) can be routed. + */ + if (route_left) + { + /* If switch value has not been assigned, assign it arbitrarily. */ + const size_t lhs_switch = as_waksman_get_canonical_row_idx(lo, to_route); + if (routing[left].find(lhs_switch) == routing[left].end()) + { + routing[left][lhs_switch] = false; + } + const bool lhs_switch_setting = routing[left][lhs_switch]; + const bool use_top = as_waksman_get_top_bottom_decision_from_switch_setting(lo, to_route, lhs_switch_setting); + const size_t t = as_waksman_switch_output(subnetwork_size, lo, lhs_switch, use_top); + if (permutation.get(to_route) == hi) + { + /** + * We have routed to the straight wire for the odd case, + * so now we back-route from it. + */ + new_permutation.set(t, hi); + new_permutation_inv.set(hi, t); + lhs_routed[to_route-lo] = true; + to_route = max_unrouted; + route_left = true; + } + else + { + const size_t rhs_switch = as_waksman_get_canonical_row_idx(lo, permutation.get(to_route)); + /** + * We know that the corresponding switch on the right-hand side + * cannot be set, so we set it according to the incoming wire. + */ + assert(routing[right].find(rhs_switch) == routing[right].end()); + routing[right][rhs_switch] = as_waksman_get_switch_setting_from_top_bottom_decision(lo, permutation.get(to_route), use_top); + const size_t tprime = as_waksman_switch_input(subnetwork_size, lo, rhs_switch, use_top); + new_permutation.set(t, tprime); + new_permutation_inv.set(tprime, t); + + lhs_routed[to_route-lo] = true; + to_route = as_waksman_other_output_position(lo, permutation.get(to_route)); + route_left = false; + } + } + else + { + /** + * We have arrived on the right-hand side, so the switch setting is fixed. + * Next, we back route from here. + */ + const size_t rhs_switch = as_waksman_get_canonical_row_idx(lo, to_route); + const size_t lhs_switch = as_waksman_get_canonical_row_idx(lo, permutation_inv.get(to_route)); + assert(routing[right].find(rhs_switch) != routing[right].end()); + const bool rhs_switch_setting = routing[right][rhs_switch]; + const bool use_top = as_waksman_get_top_bottom_decision_from_switch_setting(lo, to_route, rhs_switch_setting); + const bool lhs_switch_setting = as_waksman_get_switch_setting_from_top_bottom_decision(lo, permutation_inv.get(to_route), use_top); + + /* The value on the left-hand side is either the same or not set. */ + auto it = routing[left].find(lhs_switch); + assert(it == routing[left].end() || it->second == lhs_switch_setting); + routing[left][lhs_switch] = lhs_switch_setting; + + const size_t t = as_waksman_switch_input(subnetwork_size, lo, rhs_switch, use_top); + const size_t tprime = as_waksman_switch_output(subnetwork_size, lo, lhs_switch, use_top); + new_permutation.set(tprime, t); + new_permutation_inv.set(t, tprime); + + lhs_routed[permutation_inv.get(to_route)-lo] = true; + to_route = as_waksman_other_input_position(lo, permutation_inv.get(to_route)); + route_left = true; + } + + /* If the next packet to be routed hasn't been routed before, then try routing it. */ + if (!route_left || !lhs_routed[to_route-lo]) + { + continue; + } + + /* Otherwise just find the next unrouted packet. */ + while (max_unrouted > lo && lhs_routed[max_unrouted-lo]) + { + --max_unrouted; + } + + if (max_unrouted < lo || (max_unrouted == lo && lhs_routed[0])) /* lhs_routed[0] = corresponds to lo shifted by lo */ + { + /* All routed! */ + break; + } + else + { + to_route = max_unrouted; + route_left = true; + } + } + + if (subnetwork_size % 2 == 0) + { + /* Remove the AS-Waksman switch with the fixed value. */ + routing[left].erase(hi-1); + } + + const size_t d = as_waksman_top_height(subnetwork_size); + const integer_permutation new_permutation_upper = new_permutation.slice(lo, lo + d - 1); + const integer_permutation new_permutation_lower = new_permutation.slice(lo + d, hi); + + const integer_permutation new_permutation_inv_upper = new_permutation_inv.slice(lo, lo + d - 1); + const integer_permutation new_permutation_inv_lower = new_permutation_inv.slice(lo + d, hi); + + as_waksman_route_inner(left+1, right-1, lo, lo + d - 1, new_permutation_upper, new_permutation_inv_upper, routing); + as_waksman_route_inner(left+1, right-1, lo + d, hi, new_permutation_lower, new_permutation_inv_lower, routing); + } +} + +as_waksman_routing get_as_waksman_routing(const integer_permutation &permutation) +{ + const size_t num_packets = permutation.size(); + const size_t width = as_waksman_num_columns(num_packets); + + as_waksman_routing routing(width); + as_waksman_route_inner(0, width-1, 0, num_packets-1, permutation, permutation.inverse(), routing); + return routing; +} + +bool valid_as_waksman_routing(const integer_permutation &permutation, const as_waksman_routing &routing) +{ + const size_t num_packets = permutation.size(); + const size_t width = as_waksman_num_columns(num_packets); + as_waksman_topology neighbors = generate_as_waksman_topology(num_packets); + + integer_permutation curperm(num_packets); + + for (size_t column_idx = 0; column_idx < width; ++column_idx) + { + integer_permutation nextperm(num_packets); + for (size_t packet_idx = 0; packet_idx < num_packets; ++packet_idx) + { + size_t routed_packet_idx; + if (neighbors[column_idx][packet_idx].first == neighbors[column_idx][packet_idx].second) + { + routed_packet_idx = neighbors[column_idx][packet_idx].first; + } + else + { + auto it = routing[column_idx].find(packet_idx); + auto it2 = routing[column_idx].find(packet_idx-1); + assert((it != routing[column_idx].end()) ^ (it2 != routing[column_idx].end())); + const bool switch_setting = (it != routing[column_idx].end() ? it->second : it2->second); + + routed_packet_idx = (switch_setting ? neighbors[column_idx][packet_idx].second : neighbors[column_idx][packet_idx].first); + } + + nextperm.set(routed_packet_idx, curperm.get(packet_idx)); + } + + curperm = nextperm; + } + + return (curperm == permutation.inverse()); +} + +} // libsnark diff --git a/privacy/zsl/zsl/snark/libsnark/src/common/routing_algorithms/as_waksman_routing_algorithm.hpp b/privacy/zsl/zsl/snark/libsnark/src/common/routing_algorithms/as_waksman_routing_algorithm.hpp new file mode 100644 index 0000000..073bda1 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/common/routing_algorithms/as_waksman_routing_algorithm.hpp @@ -0,0 +1,132 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for functionality for routing on an arbitrary-size (AS) Waksman network. + + AS-Waksman networks were introduced in \[BD02]. An AS-Waksman network for + N packets is recursively defined as follows: place a column of floor(N/2) switches on + the left, and a column of floor(N/2) switches on the right; then place two AS-Waksman + sub-networks, for floor(N/2) and ceil(N/2) packets respectively, in the middle. + + Note that unlike for Beneš networks where each switch handles routing + of one packet to one of its two possible destinations, AS-Waksman + network employs switches with two input ports and two output ports + and operate either in "straight" or "cross mode". + + Routing is performed in a way that is similar to routing on Benes networks: + one first computes the switch settings for the left and right columns, + and then one recursively computes routings for the top and bottom sub-networks. + More precisely, as in \[BD02], we treat the problem of determining the switch + settings of the left and right columns as a 2-coloring problem on a certain + bipartite graph. The coloring is found by performing a depth-first search on + the graph and alternating the color at every step. For performance reasons + the graph in our implementation is implicitly represented. + + References: + + \[BD02]: + "On arbitrary size {W}aksman networks and their vulnerability", + Bruno Beauquier, Eric Darrot, + Parallel Processing Letters 2002 + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef AS_WAKSMAN_ROUTING_ALGORITHM_HPP_ +#define AS_WAKSMAN_ROUTING_ALGORITHM_HPP_ + +#include +#include +#include + +#include "common/utils.hpp" +#include "common/data_structures/integer_permutation.hpp" + +namespace libsnark { + +/** + * When laid out on num_packets \times num_columns grid, each switch + * occupies two positions: its top input and output ports are at + * position (column_idx, row_idx) and the bottom input and output + * ports are at position (column_idx, row_idx+1). + * + * We call the position assigned to the top ports of a switch its + * "canonical" position. + */ + +/** + * A data structure that stores the topology of an AS-Waksman network. + * + * For a given column index column_idx and packet index packet_idx, + * as_waksman_topology[column_idx][packet_idx] specifies the two + * possible destinations at column_idx+1-th column where the + * packet_idx-th packet in the column_idx-th column could be routed + * after passing the switch, which has (column_idx, packet_idx) as one + * of its occupied positions. + * + * This information is stored as a pair of indices, where: + * - the first index denotes the destination when the switch is + * operated in "straight" setting, and + * - the second index denotes the destination when the switch is + * operated in "cross" setting. + * + * If no switch occupies a position (column_idx, packet_idx), + * i.e. there is just a wire passing through that position, then the + * two indices are set to be equal and the packet is always routed to + * the specified destination at the column_idx+1-th column. + */ +typedef std::vector > > as_waksman_topology; + +/** + * A routing assigns a bit to each switch in the AS-Waksman routing network. + * + * More precisely: + * + * - as_waksman_routing[column_idx][packet_idx]=false, if switch with + * canonical position of (column_idx,packet_idx) is set to + * "straight" setting, and + * + * - as_waksman_routing[column_idx][packet_idx]=true, if switch with + * canonical position of (column_idx,packet_idx) is set to "cross" + * setting. + * + * Note that as_waksman_routing[column_idx][packet_idx] does contain + * entries for the positions associated with the bottom ports of the + * switches, i.e. only canonical positions are present. + */ +typedef std::vector > as_waksman_routing; + +/** + * Return the number of (switch) columns in a AS-Waksman network for a given number of packets. + * + * For example: + * - as_waksman_num_columns(2) = 1, + * - as_waksman_num_columns(3) = 3, + * - as_waksman_num_columns(4) = 3, + * and so on. + */ +size_t as_waksman_num_columns(const size_t num_packets); + +/** + * Return the topology of an AS-Waksman network for a given number of packets. + * + * See as_waksman_topology (above) for details. + */ +as_waksman_topology generate_as_waksman_topology(const size_t num_packets); + +/** + * Route the given permutation on an AS-Waksman network of suitable size. + */ +as_waksman_routing get_as_waksman_routing(const integer_permutation &permutation); + +/** + * Check if a routing "implements" the given permutation. + */ +bool valid_as_waksman_routing(const integer_permutation &permutation, const as_waksman_routing &routing); + +} // libsnark + +#endif // AS_WAKSMAN_ROUTING_ALGORITHM_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/common/routing_algorithms/benes_routing_algorithm.cpp b/privacy/zsl/zsl/snark/libsnark/src/common/routing_algorithms/benes_routing_algorithm.cpp new file mode 100644 index 0000000..d787ab1 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/common/routing_algorithms/benes_routing_algorithm.cpp @@ -0,0 +1,316 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for functionality for routing on a Benes network. + + See benes_routing_algorithm.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include "common/routing_algorithms/benes_routing_algorithm.hpp" +#include + +namespace libsnark { + +/** + * Compute the mask for all the cross edges originating at a + * particular column. + * + * Namely, the packet (column_idx, row_idx) (with column_idx < + * num_columns) can be routed to two destinations: + * + * - (column_idx+1, row_idx), if the switch handling that packet is + * set to the "straight" setting, and + * + * - (column_idx+1, row_idx XOR benes_cross_edge_mask(dimension, + * column_idx)) if the switch handling that packet is set to "cross" + * setting. + * + * For example, all cross edges in the 0-th column flip the most + * significant bit of row_idx. + */ +size_t benes_cross_edge_mask(const size_t dimension, const size_t column_idx) +{ + return (column_idx < dimension ? 1ul<<(dimension-1-column_idx) : 1ul<<(column_idx-dimension)); +} + +/** + * Return the specified destination of packet of the left-hand side of + * the routing network, based on the subnetwork (recall that each + * packet has two possible destinations -- one at the top subnetwork + * and one at the bottom subnetwork). + * + * That is for a packet located at column_idx-th column and row_idx-th + * row, return: + * + * - row_idx' of the destination packet (column_idx+1, row_idx') at + * the top subnetwork (if use_top = true) + * + * - row_idx' of the destination packet (column_idx+1, row_idx') at + * the bottom subnetwork (if use_top = false) + */ +size_t benes_lhs_packet_destination(const size_t dimension, const size_t column_idx, const size_t row_idx, const bool use_top) +{ + const size_t mask = benes_cross_edge_mask(dimension, column_idx); + return (use_top ? row_idx & ~mask : row_idx | mask); +} + +/** + * Return the specified source of packet of the right-hand side of the + * routing network, based on the subnetwork (recall that each packet + * has two possible source packets -- one at the top subnetwork and + * one at the bottom subnetwork). + * + * That is for a packet located at column_idx-th column and row_idx-th + * row, return: + * + * - row_idx' of the destination packet (column_idx-1, row_idx') at + * the top subnetwork (if use_top = true) + * + * - row_idx' of the destination packet (column_idx-1, row_idx') at + * the bottom subnetwork (if use_top = false) + */ +size_t benes_rhs_packet_source(const size_t dimension, const size_t column_idx, const size_t row_idx, const bool use_top) +{ + return benes_lhs_packet_destination(dimension, column_idx-1, row_idx, use_top); /* by symmetry */ +} + +/** + * For a switch located at column_idx-th column and row_idx-th row, + * return the switch setting that would route its packet using the top + * subnetwork. + */ +bool benes_get_switch_setting_from_subnetwork(const size_t dimension, const size_t column_idx, const size_t row_idx, const bool use_top) +{ + return (row_idx != benes_lhs_packet_destination(dimension, column_idx, row_idx, use_top)); +} + +/** + * A packet column_idx-th column and row_idx-th row of the routing + * network has two destinations (see comment by + * benes_cross_edge_mask), this returns row_idx' of the "cross" + * destination. + */ +size_t benes_packet_cross_destination(const size_t dimension, const size_t column_idx, const size_t row_idx) +{ + const size_t mask = benes_cross_edge_mask(dimension, column_idx); + return row_idx ^ mask; +} + +/** + * A packet column_idx-th column and row_idx-th row of the routing + * network has two source packets that could give rise to it (see + * comment by benes_cross_edge_mask), this returns row_idx' of the + * "cross" source packet. + */ +size_t benes_packet_cross_source(const size_t dimension, const size_t column_idx, const size_t packet_idx) +{ + return benes_packet_cross_destination(dimension, column_idx-1, packet_idx); /* by symmetry */ +} + +size_t benes_num_columns(const size_t num_packets) +{ + const size_t dimension = log2(num_packets); + assert(num_packets == 1ul< +std::vector > route_by_benes(const benes_routing &routing, const std::vector &start) +{ + const size_t num_packets = start.size(); + const size_t num_columns = benes_num_columns(num_packets); + const size_t dimension = log2(num_packets); + + std::vector > res(num_columns+1, std::vector(num_packets)); + res[0] = start; + + for (size_t column_idx = 0; column_idx < num_columns; ++column_idx) + { + const size_t mask = benes_cross_edge_mask(dimension, column_idx); + + for (size_t packet_idx = 0; packet_idx < num_packets; ++packet_idx) + { + size_t next_packet_idx = (routing[column_idx][packet_idx] == false) ? packet_idx : packet_idx ^ mask; + res[column_idx+1][next_packet_idx] = res[column_idx][packet_idx]; + } + } + + return res; +} + +bool valid_benes_routing(const integer_permutation &permutation, const benes_routing &routing) +{ + const size_t num_packets = permutation.size(); + const size_t num_columns = benes_num_columns(num_packets); + + std::vector input_packets(num_packets); + for (size_t packet_idx = 0; packet_idx < num_packets; ++packet_idx) + { + input_packets[packet_idx] = packet_idx; + } + + const std::vector > routed_packets = route_by_benes(routing, input_packets); + + for (size_t packet_idx = 0; packet_idx < num_packets; ++packet_idx) + { + if (routed_packets[num_columns][permutation.get(packet_idx)] != input_packets[packet_idx]) + { + return false; + } + } + + return true; +} + +} // libsnark diff --git a/privacy/zsl/zsl/snark/libsnark/src/common/routing_algorithms/benes_routing_algorithm.hpp b/privacy/zsl/zsl/snark/libsnark/src/common/routing_algorithms/benes_routing_algorithm.hpp new file mode 100644 index 0000000..4d33f90 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/common/routing_algorithms/benes_routing_algorithm.hpp @@ -0,0 +1,91 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for functionality for routing on a Benes network. + + Routing is performed via the standard algorithm that computes a + routing by first computing the switch settings for the left and right + columns of the network and then recursively computing routings for + the top half and the bottom half of the network (each of which is a + Benes network of smaller size). + + References: + + \[Ben65]: + "Mathematical theory of connecting networks and telephone traffic", + Václav E. Beneš, + Academic Press 1965 + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef BENES_ROUTING_ALGORITHM_HPP_ +#define BENES_ROUTING_ALGORITHM_HPP_ + +#include + +#include "common/data_structures/integer_permutation.hpp" +#include "common/utils.hpp" + +namespace libsnark { + +/** + * A data structure that stores the topology of a Benes network. + * + * For a given column index column_idx and packet index packet_idx, + * benes_topology[column_idx][packet_idx] specifies the two possible + * destinations where the packet_idx-th packet in the column_idx-th column + * could be routed. This information is stored as a pair of indices, where: + * - the first index denotes the destination when the switch is in "straight" mode, and + * - the second index denotes the destination when the switch is in "cross" mode. + * + * (The topology has a very succinct description and can be easily + * queried at an arbitrary position, see implementation of + * generate_benes_topology for details.) + */ +typedef std::vector > > benes_topology; + +/** + * A routing assigns a bit to each switch in a Benes network. + * + * For a d-dimensional Benes network, the switch bits are stored in a + * vector consisting of 2*d entries, and each entry contains 2^d bits. + * That is, we have one switch per packet, but switch settings are not + * independent. + */ +typedef std::vector benes_routing; + +/** + * Return the number of (switch) columns in a Benes network for a given number of packets. + * + * For example: + * - benes_num_columns(2) = 2, + * - benes_num_columns(4) = 4, + * - benes_num_columns(8) = 6, + * and so on. + */ +size_t benes_num_columns(const size_t num_packets); + +/** + * Return the topology of a Benes network for a given number of packets. + * + * See benes_topology (above) for details. + */ +benes_topology generate_benes_topology(const size_t num_packets); + +/** + * Route the given permutation on a Benes network of suitable size. + */ +benes_routing get_benes_routing(const integer_permutation &permutation); + +/** + * Check if a routing "implements" the given permutation. + */ +bool valid_benes_routing(const integer_permutation &permutation, const benes_routing &routing); + +} // libsnark + +#endif // BENES_ROUTING_ALGORITHM_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/common/routing_algorithms/profiling/profile_routing_algorithms.cpp b/privacy/zsl/zsl/snark/libsnark/src/common/routing_algorithms/profiling/profile_routing_algorithms.cpp new file mode 100644 index 0000000..4d386c2 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/common/routing_algorithms/profiling/profile_routing_algorithms.cpp @@ -0,0 +1,63 @@ +/** @file + ***************************************************************************** + + Functions to profile the algorithms that route on Benes and AS-Waksman networks. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include + +#include "common/profiling.hpp" +#include "common/routing_algorithms/as_waksman_routing_algorithm.hpp" +#include "common/routing_algorithms/benes_routing_algorithm.hpp" + +using namespace libsnark; + +void profile_benes_algorithm(const size_t n) +{ + printf("* Size: %zu\n", n); + + assert(n == 1ul< + +#include "common/profiling.hpp" +#include "common/routing_algorithms/benes_routing_algorithm.hpp" +#include "common/routing_algorithms/as_waksman_routing_algorithm.hpp" + +using namespace libsnark; + +/** + * Test Benes network routing for all permutations on 2^log2(N) elements. + */ +void test_benes(const size_t N) +{ + integer_permutation permutation(1ul << log2(N)); + + do { + const benes_routing routing = get_benes_routing(permutation); + assert(valid_benes_routing(permutation, routing)); + } while (permutation.next_permutation()); +} + +/** + * Test AS-Waksman network routing for all permutations on N elements. + */ +void test_as_waksman(const size_t N) +{ + integer_permutation permutation(N); + + do { + const as_waksman_routing routing = get_as_waksman_routing(permutation); + assert(valid_as_waksman_routing(permutation, routing)); + } while (permutation.next_permutation()); +} + +int main(void) +{ + start_profiling(); + + enter_block("Test routing algorithms"); + + enter_block("Test Benes network routing algorithm"); + size_t bn_size = 8; + print_indent(); printf("* for all permutations on %zu elements\n", bn_size); + test_benes(bn_size); + leave_block("Test Benes network routing algorithm"); + + + enter_block("Test AS-Waksman network routing algorithm"); + size_t asw_max_size = 9; + for (size_t i = 2; i <= asw_max_size; ++i) + { + print_indent(); printf("* for all permutations on %zu elements\n", i); + test_as_waksman(i); + } + leave_block("Test AS-Waksman network routing algorithm"); + + leave_block("Test routing algorithms"); +} diff --git a/privacy/zsl/zsl/snark/libsnark/src/common/routing_algorithms/tests/test_routing_algorithms.py b/privacy/zsl/zsl/snark/libsnark/src/common/routing_algorithms/tests/test_routing_algorithms.py new file mode 100644 index 0000000..239b22e --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/common/routing_algorithms/tests/test_routing_algorithms.py @@ -0,0 +1,406 @@ +#!/usr/bin/env python + +from __future__ import division +import math +import itertools +import random +import time +from collections import defaultdict + +def top_height(sz): + """Returns the height of the top part of size `sz' AS-Waksman network.""" + return sz // 2 + +def bottom_height(sz): + """Returns the height of the bottom part of size `sz' AS-Waksman + network.""" + return sz - top_height(sz) + +def switch_output(base, pos, sz, top): + """The recursive AS-Waksman construction AS-Waksman(sz) places two + lines of floor(sz/2) switches each and connects the outputs of + AS-Waksman(floor(sz/2)) and AS-Waksman(ceil(sz/2)) in between + them. + + Return the output wire of left-hand side switch `pos'(relative to + the base level `base' in the recursive call) in size `sz' + AS-Waksman network. + + If `top' = True, return the top wire, otherwise return bottom + wire. """ + relpos = pos - base + assert relpos % 2 == 0 and relpos + 1 < sz + if top: + return base + (relpos // 2) + else: + return base + top_height(sz) + (relpos // 2) + +def switch_input(base, pos, sz, top): + """This function is symmetric to switch_output(base, pos, sz, top), + but returns the input wire of the right-hand side switch (rather than + the output wire of the left-hand side switch).""" + # because of symmetry this coincides with switch_output + return switch_output(base, pos, sz, top) + +def width(sz): + """Returns width of size `sz' AS-Waksman network. For example, width(2) = + 1, width(3) = 3, width(4) = 3.""" + return 2*int(math.ceil(math.log(sz, 2)))-1 + +def construct_as_waksman_topology(n): + """Returns a pair (neighbors, switches) describing the topology of + AS-Waksman network of size n. + + neigbhors[i][j] lists the possible locations where a wire, at + position j before going through the i-th column, could be routed to + after passing through the column. neighbors[i][j] is a length 1 + list for straight wires and length 2 list for switches, where the + first element denotes the destination when the switch is operated + in "straight" mode and the second element denotes the destination + for the "cross" mode. + + switches[i] is the dictionary, whose keys are all positions of the + switches at the i-th column and keys are switch settings. This + function only returns the topology, so switch settings are all set + to be None.""" + + assert n > 1 + w = width(n) + + neighbors = [{} for i in xrange(w)] + switches = [{} for i in xrange(w)] + + def construct_as_waksman_topology_inner(left, right, lo, hi, rhs_dests): + """Construct AS-Waksman subnetwork occupying switch columns [left, + left+1, ..., right] that will route left-hand side inputs [lo, + lo+1, ..., hi] to right-hand side destinations rhs_dests[0], + rhs_dests[1], ..., rhs_dests[hi-lo+1]. (That is, rhs_dests are + 0-indexed w.r.t. base of lo.) + + This function will fill out neighbors[left], + neighbors[right-1] and add switches in columns switches[left], + switches[right].""" + if left > right: + return + + sz = (hi - lo + 1) + assert len(rhs_dests) == sz + + assert (right - left + 1) >= width(sz) + + if right - left + 1 > width(sz): + # If there is more space for the routing network than + # required, just add straight edges. This also takes care + # of size 1 routing network base case. + for i in xrange(lo, hi + 1): + neighbors[left][i] = [i] + neighbors[right][i] = [rhs_dests[i - lo]] + # Recurse to construct the corresponding subnetwork. + construct_as_waksman_topology_inner(left + 1, right - 1, lo, hi, range(lo, hi+1)) + elif sz == 2: + # Non-trivial base case: routing a 2-element permutation. + neighbors[left][lo] = [rhs_dests[0], rhs_dests[1]] + neighbors[left][hi] = [rhs_dests[1], rhs_dests[0]] + switches[left][lo] = None + else: + # Networks of size sz > 2 are handled by adding two lines + # of switches alongside the network and recursing. + new_rhs_dests = [None] * sz + + # This adds floor(sz/2) switches alongside the network. As + # per AS-Waksman construction one of the switches in the even + # case can be eliminated (i.e. set to be constant); this + # will be handled later. + for i in xrange(lo, hi, 2): + switches[left][i] = None + switches[right][i] = None + + neighbors[left][i] = [switch_output(lo, i, sz, True), switch_output(lo, i, sz, False)] + neighbors[left][i+1] = [switch_output(lo, i, sz, False), switch_output(lo, i, sz, True)] + + new_rhs_dests[switch_input(lo, i, sz, True)-lo] = i + new_rhs_dests[switch_input(lo, i, sz, False)-lo] = i+1 + + neighbors[right][i] = [rhs_dests[i-lo], rhs_dests[i+1-lo]] + neighbors[right][i+1] = [rhs_dests[i+1-lo], rhs_dests[i-lo]] + + if sz % 2 == 1: + # Odd special case: the last wire is not connected to + # any of the switches and just routed straight. + neighbors[left][hi] = [hi] + neighbors[right][hi] = [rhs_dests[hi-lo]] + new_rhs_dests[hi-lo] = hi + else: + # Even special case: fix the bottom-most LHS switch to + # a constant "straight" setting. + neighbors[left][hi-1] = [switch_output(lo, hi-1, sz, True)] + neighbors[left][hi] == [switch_output(lo, hi-1, sz, False)] + + d = top_height(sz) + construct_as_waksman_topology_inner(left + 1, right - 1, lo, lo + d - 1, new_rhs_dests[:d]) + construct_as_waksman_topology_inner(left + 1, right - 1, lo + d, hi, new_rhs_dests[d:]) + + construct_as_waksman_topology_inner(0, w-1, 0, n-1, range(n)) + return (neighbors, switches) + +def switch_position_from_wire_position(base, global_pos): + """Each switch occupies two wire positions (pos, pos+1); given a wire + position (plus, a base for offsetting the switch within subnetwork + that created it), this function returns the "canonical" position for + the switch, that is, the "upper" position global_pos. + + global_pos is assumed to be input position for the LHS switches + and output position for the RHS switches.""" + return ((global_pos - base) & ~1) + base + +def get_switch_value_from_top_bottom_decision(base, global_pos, top): + """Return a switch value that makes switch s = + switch_position_from_wire_position(base, global_pos) to route the + wire global_pos via the top (if top = True), resp., bottom (if top + = False) subnetwork. + + global_pos is assumed to be input position for the LHS switches + and output position for the RHS switches.""" + s = switch_position_from_wire_position(base, global_pos) + return (s == global_pos) ^ top + +def get_top_bottom_decision_from_switch_value(base, global_pos, val): + """Returns True if the switch s = + switch_position_from_wire_position(base, global_pos) when set to + "straight" (if val = True), resp., "cross" (if val = False), + routes the wire global_pos via the top subnetwork. + + global_pos is assumed to be input position for the LHS switches + and output position for the RHS switches.""" + s = switch_position_from_wire_position(base, global_pos) + return (s == global_pos) ^ val + +def other_output_position(base, global_pos): + """Given an output position of a RHS switch, calculate and return the + output position of the other wire also connected to this switch.""" + switch = switch_position_from_wire_position(base, global_pos) + return (1 - (global_pos - switch)) + switch + +def other_input_position(base, global_pos): + """Given an input position of a LHS switch, calculate and return the + output position of the other wire also connected to this switch.""" + # Exploiting symmetry here, this is the same as the output + # position for the corresponding RHS switch. + return other_output_position(base, global_pos) + +def route_as_waksman(n, network, pi): + """Return AS-Waksman switch settings that implement the given + permutation.""" + assert n > 1 + w = width(n) + neighbors, switches = network + + piinv = [None for i in xrange(n)] + for i in xrange(n): + piinv[pi[i]] = i + + def route_as_waksman_inner(left, right, lo, hi, pi, piinv): + """Get AS-Waksman switch settings for the subnetwork occupying switch + columns [left, left+1, ..., right] that will route left-hand + side inputs [lo, lo+1, ..., hi] to right-hand side + destinations pi[lo], pi[lo+1], ... pi[hi].""" + if left > right: + return + + sz = (hi - lo + 1) + assert (right - left + 1) >= width(sz) + + if right - left + 1 > width(sz): + # If there is more space for the routing network than + # required, then the topology for this subnetwork includes + # straight edges along its sides and no switches, so we + # just recurse. + route_as_waksman_inner(left + 1, right - 1, lo, hi, pi, piinv) + elif sz == 2: + # Non-trivial base case: switch settings for a 2-element permutation. + assert set([pi[lo], pi[lo+1]]) == set([lo, lo+1]) + switches[left][lo] = (pi[lo] != lo) + else: + newpi = defaultdict(lambda : None) + newpiinv = defaultdict(lambda : None) + # Our algorithm will first assign a setting for a LHS + # switch, route its target to RHS, which will enforce a + # RHS switch setting. Then, we back-route the RHS value + # back to LHS. If this enforces a LHS switch setting, then + # forward-route that, otherwise we will select the next + # value from LHS to route. + lhs_routed = defaultdict(lambda : False) + + if sz % 2 == 1: + # If size is odd we first deal with the bottom-most + # straight wire, which is not connected to any of the + # switches at this level of recursion and just passed + # into the lower subnetwork. + if pi[hi] == hi: + # Easy case: it is routed directly to the + # bottom-most wire on RHS, so no switches need to + # be touched. + newpi[hi] = hi + newpiinv[hi] = hi + to_route = hi - 1 + route_left = True + else: + # Other case: the straight wire is routed to a + # switch on RHS, so route the other value from + # that switch using the lower subnetwork. + rhs_switch = switch_position_from_wire_position(lo, pi[hi]) + rhs_switch_val = get_switch_value_from_top_bottom_decision(lo, pi[hi], False) + switches[right][rhs_switch] = rhs_switch_val + tprime = switch_input(lo, rhs_switch, sz, False) + newpi[hi] = tprime + newpiinv[tprime] = hi + + to_route = other_output_position(lo, pi[hi]) + route_left = False + + lhs_routed[hi] = True + max_unrouted = hi - 1 + else: + # If n is even, then the bottom-most switch (one + # freely set in Benes construction) is fixed to a + # constant straight setting. So we route wire hi + # accordingly. + switches[left][hi-1] = False + to_route = hi + route_left = True + max_unrouted = hi + + while True: + # We maintain invariant that wire `to_route' on LHS + # (if route_left = True), resp., rhs (if route_left = + # False) can be routed. + if route_left: + # If switch value hasn't been assigned, assign it arbitrarily + lhs_switch = switch_position_from_wire_position(lo, to_route) + if switches[left][lhs_switch] is None: + switches[left][lhs_switch] = False + lhs_switch_val = switches[left][lhs_switch] + use_top = get_top_bottom_decision_from_switch_value(lo, to_route, lhs_switch_val) + + t = switch_output(lo, lhs_switch, sz, use_top) + if pi[to_route] == hi: + # We have routed to the straight wire for the + # odd case, so back-route from it. + newpi[t] = hi + newpiinv[hi] = t + + lhs_routed[to_route] = True + to_route = max_unrouted + route_left = True + else: + rhs_switch = switch_position_from_wire_position(lo, pi[to_route]) + # We know that the corresponding switch on RHS + # cannot be set, so set it according to our + # incoming wire. + assert switches[right][rhs_switch] is None + + switches[right][rhs_switch] = get_switch_value_from_top_bottom_decision(lo, pi[to_route], use_top) + tprime = switch_input(lo, rhs_switch, sz, use_top) + newpi[t] = tprime + newpiinv[tprime] = t + + lhs_routed[to_route] = True + to_route = other_output_position(lo, pi[to_route]) + route_left = False + else: + # We have arrived on RHS side, so our switch + # setting is fixed. We will just back-route from + # that. + rhs_switch = switch_position_from_wire_position(lo, to_route) + lhs_switch = switch_position_from_wire_position(lo, piinv[to_route]) + + assert switches[right][rhs_switch] is not None + rhs_switch_val = switches[right][rhs_switch] + use_top = get_top_bottom_decision_from_switch_value(lo, to_route, rhs_switch_val) + lhs_switch_val = get_switch_value_from_top_bottom_decision(lo, piinv[to_route], use_top) + + # The value on LHS is either the same or unset + assert switches[left][lhs_switch] in [None, lhs_switch_val] + + switches[left][lhs_switch] = lhs_switch_val + t = switch_input(lo, rhs_switch, sz, use_top) + tprime = switch_output(lo, lhs_switch, sz, use_top) + newpi[tprime] = t + newpiinv[t] = tprime + + lhs_routed[piinv[to_route]] = True + to_route = other_input_position(lo, piinv[to_route]) + route_left = True + + # If the next item to be routed hasn't been routed + # before, then try routing it. + if not route_left or not lhs_routed[to_route]: + continue + + # Otherwise just find the next unrouted item. + while max_unrouted >= lo and lhs_routed[max_unrouted]: + max_unrouted -= 1 + + if max_unrouted < lo: + # All routed + break + else: + to_route = max_unrouted + route_left = True + + d = top_height(sz) + route_as_waksman_inner(left + 1, right - 1, lo, lo + d - 1, newpi, newpiinv) + route_as_waksman_inner(left + 1, right - 1, lo + d, hi, newpi, newpiinv) + + route_as_waksman_inner(0, w-1, 0, n-1, pi, piinv) + +def check_as_waksman_routing(network, pi): + assert n > 1 + w = width(n) + neighbors, switches = network + + piinv = [None for i in xrange(n)] + for i in xrange(n): + piinv[pi[i]] = i + curperm = range(n) + for i in xrange(w): + nextperm = [None] * n + for j in xrange(n): + assert len(neighbors[i][j]) in [1, 2] + + if len(neighbors[i][j]) == 1: + nextperm[neighbors[i][j][0]] = curperm[j] + else: + assert (j in switches[i]) ^ ((j - 1) in switches[i]) + switchval = switches[i][j] if j in switches[i] else switches[i][j-1] + nextperm[neighbors[i][j][1 if switchval else 0]] = curperm[j] + curperm = nextperm + + return curperm == piinv + +def test_routing_of_all_permutations(n): + for pi in itertools.permutations(range(n)): + print n, pi + network = construct_as_waksman_topology(n) + route_as_waksman(n, network, pi) + assert check_as_waksman_routing(network, pi) + +def profile_routing_algorithm_speed(k_min, k_max): + prev_t = None + for k in xrange(k_min, k_max+1): + n = 2**k + pi = range(n) + random.shuffle(pi) + network = construct_network(n) + t = time.time() + route(n, network, pi) + t = time.time() - t + assert check_as_waksman_routing(network, pi) + print n, t, (t/prev_t if prev_t else "-"), t/(n * k) + prev_t = t + + +if __name__ == '__main__': + for n in xrange(2, 9): + test_routing_of_all_permutations(n) + #profile_routing_algorithm_speed(2, 16) diff --git a/privacy/zsl/zsl/snark/libsnark/src/common/serialization.hpp b/privacy/zsl/zsl/snark/libsnark/src/common/serialization.hpp new file mode 100644 index 0000000..bea7feb --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/common/serialization.hpp @@ -0,0 +1,106 @@ +/** @file + ***************************************************************************** + + Declaration of serialization routines and constants. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef SERIALIZATION_HPP_ +#define SERIALIZATION_HPP_ + +#include +#include +#include +#include +#include + +namespace libsnark { + +/* + * @todo + * The serialization is fragile. Shoud be rewritten using a standard, portable-format + * library like boost::serialize. + * + * However, for now the following conventions are used within the code. + * + * All algebraic objects support either binary or decimal output using + * the standard C++ stream operators (operator<<, operator>>). + * + * The binary mode is activated by defining a BINARY_OUTPUT + * preprocessor macro (e.g. g++ -DBINARY_OUTPUT ...). + * + * Binary output assumes that the stream is to be binary read at its + * current position so any white space should be consumed beforehand. + * + * Consecutive algebraic objects are separated by OUTPUT_NEWLINE and + * within themselves (e.g. X and Y coordinates for field elements) with + * OUTPUT_SEPARATOR (as defined below). + * + * Therefore to dump two integers, two Fp elements and another integer + * one would: + * + * out << 3 << "\n"; + * out << 4 << "\n"; + * out << FieldT(56) << OUTPUT_NEWLINE; + * out << FieldT(78) << OUTPUT_NEWLINE; + * out << 9 << "\n"; + * + * Then reading back it its reader's responsibility (!) to consume "\n" + * after 4, but Fp::operator<< will correctly consume OUTPUT_NEWLINE. + * + * The reader should also consume "\n" after 9, so that another field + * element can be properly chained. This is especially important for + * binary output. + * + * The binary serialization of algebraic objects is currently *not* + * portable between machines of different word sizes. + */ + +#ifdef BINARY_OUTPUT +#define OUTPUT_NEWLINE "" +#define OUTPUT_SEPARATOR "" +#else +#define OUTPUT_NEWLINE "\n" +#define OUTPUT_SEPARATOR " " +#endif + +inline void consume_newline(std::istream &in); +inline void consume_OUTPUT_NEWLINE(std::istream &in); +inline void consume_OUTPUT_SEPARATOR(std::istream &in); + +inline void output_bool(std::ostream &out, const bool b); +inline void input_bool(std::istream &in, bool &b); + +inline void output_bool_vector(std::ostream &out, const std::vector &v); +inline void input_bool_vector(std::istream &in, std::vector &v); + +template +T reserialize(const T &obj); + +template +std::ostream& operator<<(std::ostream& out, const std::vector &v); + +template +std::istream& operator>>(std::ostream& out, std::vector &v); + +template +std::ostream& operator<<(std::ostream& out, const std::map &m); + +template +std::istream& operator>>(std::istream& in, std::map &m); + +template +std::ostream& operator<<(std::ostream& out, const std::set &s); + +template +std::istream& operator>>(std::istream& in, std::set &s); + +} // libsnark + +#include "common/serialization.tcc" + +#endif // SERIALIZATION_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/common/serialization.tcc b/privacy/zsl/zsl/snark/libsnark/src/common/serialization.tcc new file mode 100644 index 0000000..c6f67bc --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/common/serialization.tcc @@ -0,0 +1,204 @@ +/** @file + ***************************************************************************** + + Implementation of serialization routines. + + See serialization.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef SERIALIZATION_TCC_ +#define SERIALIZATION_TCC_ + +#include +#include +#include "common/utils.hpp" + +namespace libsnark { + +inline void consume_newline(std::istream &in) +{ + char c; + in.read(&c, 1); +} + +inline void consume_OUTPUT_NEWLINE(std::istream &in) +{ +#ifdef BINARY_OUTPUT + // nothing to consume + UNUSED(in); +#else + char c; + in.read(&c, 1); +#endif +} + +inline void consume_OUTPUT_SEPARATOR(std::istream &in) +{ +#ifdef BINARY_OUTPUT + // nothing to consume + UNUSED(in); +#else + char c; + in.read(&c, 1); +#endif +} + +inline void output_bool(std::ostream &out, const bool b) +{ + out << (b ? 1 : 0) << "\n"; +} + +inline void input_bool(std::istream &in, bool &b) +{ + size_t tmp; + in >> tmp; + consume_newline(in); + assert(tmp == 0 || tmp == 1); + + b = (tmp == 1 ? true : false); +} + +inline void output_bool_vector(std::ostream &out, const std::vector &v) +{ + out << v.size() << "\n"; + for (const bool b : v) + { + output_bool(out, b); + } +} + +inline void input_bool_vector(std::istream &in, std::vector &v) +{ + size_t size; + in >> size; + consume_newline(in); + v.resize(size); + for (size_t i = 0; i < size; ++i) + { + bool b; + input_bool(in, b); + v[i] = b; + } +} + +template +T reserialize(const T &obj) +{ + std::stringstream ss; + ss << obj; + T tmp; + ss >> tmp; + assert(obj == tmp); + return tmp; +} + +template +std::ostream& operator<<(std::ostream& out, const std::vector &v) +{ + static_assert(!std::is_same::value, "this does not work for std::vector"); + out << v.size() << "\n"; + for (const T& t : v) + { + out << t << OUTPUT_NEWLINE; + } + + return out; +} + +template +std::istream& operator>>(std::istream& in, std::vector &v) +{ + static_assert(!std::is_same::value, "this does not work for std::vector"); + size_t size; + in >> size; + consume_newline(in); + + v.resize(0); + for (size_t i = 0; i < size; ++i) + { + T elt; + in >> elt; + consume_OUTPUT_NEWLINE(in); + v.push_back(elt); + } + + return in; +} + +template +std::ostream& operator<<(std::ostream& out, const std::map &m) +{ + out << m.size() << "\n"; + + for (auto &it : m) + { + out << it.first << "\n"; + out << it.second << "\n"; + } + + return out; +} + +template +std::istream& operator>>(std::istream& in, std::map &m) +{ + m.clear(); + size_t size; + in >> size; + consume_newline(in); + + for (size_t i = 0; i < size; ++i) + { + T1 k; + T2 v; + in >> k; + consume_newline(in); + in >> v; + consume_newline(in); + m[k] = v; + } + + return in; +} + +template +std::ostream& operator<<(std::ostream& out, const std::set &s) +{ + out << s.size() << "\n"; + + for (auto &el : s) + { + out << el << "\n"; + } + + return out; +} + + +template +std::istream& operator>>(std::istream& in, std::set &s) +{ + s.clear(); + size_t size; + in >> size; + consume_newline(in); + + for (size_t i = 0; i < size; ++i) + { + T el; + in >> el; + consume_newline(in); + s.insert(el); + } + + return in; +} + +} + +#endif // SERIALIZATION_TCC_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/common/template_utils.hpp b/privacy/zsl/zsl/snark/libsnark/src/common/template_utils.hpp new file mode 100644 index 0000000..8dbfd26 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/common/template_utils.hpp @@ -0,0 +1,26 @@ +/** @file + ***************************************************************************** + + Declaration of functions for supporting the use of templates. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef TEMPLATE_UTILS_HPP_ +#define TEMPLATE_UTILS_HPP_ + +namespace libsnark { + +/* A commonly used SFINAE helper type */ +template +struct void_type +{ + typedef void type; +}; + +} // libsnark + +#endif // TEMPLATE_UTILS_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/common/utils.cpp b/privacy/zsl/zsl/snark/libsnark/src/common/utils.cpp new file mode 100644 index 0000000..5332769 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/common/utils.cpp @@ -0,0 +1,115 @@ +/** @file + ***************************************************************************** + Implementation of misc math and serialization utility functions + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include +#include +#include +#include +#include "common/utils.hpp" + +namespace libsnark { + +size_t log2(size_t n) +/* returns ceil(log2(n)), so 1ul< 1) + { + n >>= 1; + r++; + } + + return r; +} + +size_t to_twos_complement(int i, size_t w) +{ + assert(i >= -(1l<<(w-1))); + assert(i < (1l<<(w-1))); + return (i >= 0) ? i : i + (1l<>= 1; + } + return r; +} + +bit_vector int_list_to_bits(const std::initializer_list &l, const size_t wordsize) +{ + bit_vector res(wordsize*l.size()); + for (size_t i = 0; i < l.size(); ++i) + { + for (size_t j = 0; j < wordsize; ++j) + { + res[i*wordsize + j] = (*(l.begin()+i) & (1ul<<(wordsize-1-j))); + } + } + return res; +} + +long long div_ceil(long long x, long long y) +{ + return (x + (y-1)) / y; +} + +bool is_little_endian() +{ + uint64_t a = 0x12345678; + unsigned char *c = (unsigned char*)(&a); + return (*c = 0x78); +} + +std::string FORMAT(const std::string &prefix, const char* format, ...) +{ + const static size_t MAX_FMT = 256; + char buf[MAX_FMT]; + va_list args; + va_start(args, format); + vsnprintf(buf, MAX_FMT, format, args); + va_end(args); + + return prefix + std::string(buf); +} + +void serialize_bit_vector(std::ostream &out, const bit_vector &v) +{ + out << v.size() << "\n"; + for (size_t i = 0; i < v.size(); ++i) + { + out << v[i] << "\n"; + } +} + +void deserialize_bit_vector(std::istream &in, bit_vector &v) +{ + size_t size; + in >> size; + v.resize(size); + for (size_t i = 0; i < size; ++i) + { + bool b; + in >> b; + v[i] = b; + } +} +} // libsnark diff --git a/privacy/zsl/zsl/snark/libsnark/src/common/utils.hpp b/privacy/zsl/zsl/snark/libsnark/src/common/utils.hpp new file mode 100644 index 0000000..8d7f06a --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/common/utils.hpp @@ -0,0 +1,60 @@ +/** @file + ***************************************************************************** + Declaration of misc math and serialization utility functions + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef UTILS_HPP_ +#define UTILS_HPP_ + +#include +#include +#include +#include +#include + +namespace libsnark { + +typedef std::vector bit_vector; + +/// returns ceil(log2(n)), so 1ul< &l, const size_t wordsize); +long long div_ceil(long long x, long long y); + +bool is_little_endian(); + +std::string FORMAT(const std::string &prefix, const char* format, ...); + +/* A variadic template to suppress unused argument warnings */ +template +void UNUSED(Types&&...) {} + +#ifdef DEBUG +#define FMT FORMAT +#else +#define FMT(...) (UNUSED(__VA_ARGS__), "") +#endif + +void serialize_bit_vector(std::ostream &out, const bit_vector &v); +void deserialize_bit_vector(std::istream &in, bit_vector &v); + +template +size_t size_in_bits(const std::vector &v); + +#define ARRAY_SIZE(arr) (sizeof(arr)/sizeof(arr[0])) + +} // libsnark + +#include "common/utils.tcc" /* note that utils has a templatized part (utils.tcc) and non-templatized part (utils.cpp) */ +#endif // UTILS_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/common/utils.tcc b/privacy/zsl/zsl/snark/libsnark/src/common/utils.tcc new file mode 100644 index 0000000..f97178f --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/common/utils.tcc @@ -0,0 +1,23 @@ +/** @file + ***************************************************************************** + Implementation of templatized utility functions + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef UTILS_TCC_ +#define UTILS_TCC_ + +namespace libsnark { + +template +size_t size_in_bits(const std::vector &v) +{ + return v.size() * T::size_in_bits(); +} + +} // libsnark + +#endif // UTILS_TCC_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/constraint_profiling.cpp b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/constraint_profiling.cpp new file mode 100644 index 0000000..bc17e63 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/constraint_profiling.cpp @@ -0,0 +1,48 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for profiling constraints. + + See constraint_profiling.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include "gadgetlib1/constraint_profiling.hpp" +#include "common/profiling.hpp" + +namespace libsnark { + +size_t constraint_profiling_indent = 0; +std::vector constraint_profiling_table; + +size_t PRINT_CONSTRAINT_PROFILING() +{ + size_t accounted = 0; + print_indent(); + printf("Constraint profiling:\n"); + for (constraint_profiling_entry &ent : constraint_profiling_table) + { + if (ent.indent == 0) + { + accounted += ent.count; + } + + print_indent(); + for (size_t i = 0; i < ent.indent; ++i) + { + printf(" "); + } + printf("* Number of constraints in [%s]: %zu\n", ent.annotation.c_str(), ent.count); + } + + constraint_profiling_table.clear(); + constraint_profiling_indent = 0; + + return accounted; +} + +} diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/constraint_profiling.hpp b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/constraint_profiling.hpp new file mode 100644 index 0000000..df8a55d --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/constraint_profiling.hpp @@ -0,0 +1,42 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for profiling constraints. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef CONSTRAINT_PROFILING_HPP_ +#define CONSTRAINT_PROFILING_HPP_ + +#include +#include +#include +#include + +namespace libsnark { + +extern size_t constraint_profiling_indent; + +struct constraint_profiling_entry { + size_t indent; + std::string annotation; + size_t count; +}; + +extern std::vector constraint_profiling_table; + +#define PROFILE_CONSTRAINTS(pb, annotation) \ + for (size_t _num_constraints_before = pb.num_constraints(), _iter = (++constraint_profiling_indent, 0), _cp_pos = constraint_profiling_table.size(); \ + _iter == 0; \ + constraint_profiling_table.insert(constraint_profiling_table.begin() + _cp_pos, constraint_profiling_entry{--constraint_profiling_indent, annotation, pb.num_constraints() - _num_constraints_before}), \ + _iter = 1) + +size_t PRINT_CONSTRAINT_PROFILING(); // returns # of top level constraints + +} // libsnark + +#endif // CONSTRAINT_PROFILING_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/examples/simple_example.hpp b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/examples/simple_example.hpp new file mode 100644 index 0000000..e2a4774 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/examples/simple_example.hpp @@ -0,0 +1,23 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef SIMPLE_EXAMPLE_HPP_ +#define SIMPLE_EXAMPLE_HPP_ + +#include "relations/constraint_satisfaction_problems/r1cs/examples/r1cs_examples.hpp" + +namespace libsnark { + +template +r1cs_example gen_r1cs_example_from_protoboard(const size_t num_constraints, + const size_t num_inputs); + +} // libsnark + +#include "gadgetlib1/examples/simple_example.tcc" + +#endif // SIMPLE_EXAMPLE_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/examples/simple_example.tcc b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/examples/simple_example.tcc new file mode 100644 index 0000000..c7418f5 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/examples/simple_example.tcc @@ -0,0 +1,48 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef SIMPLE_EXAMPLE_TCC_ +#define SIMPLE_EXAMPLE_TCC_ + +#include "gadgetlib1/gadgets/basic_gadgets.hpp" + +namespace libsnark { + +/* NOTE: all examples here actually generate one constraint less to account for soundness constraint in QAP */ + +template +r1cs_example gen_r1cs_example_from_protoboard(const size_t num_constraints) +{ + const size_t new_num_constraints = num_constraints - 1; + + /* construct dummy example: inner products of two vectors */ + protoboard pb; + pb_variable_array A; + pb_variable_array B; + pb_variable res; + + // the variables on the protoboard are (ONE (constant 1 term), res, A[0], ..., A[num_constraints-1], B[0], ..., B[num_constraints-1]) + res.allocate(pb, "res"); + A.allocate(pb, new_num_constraints, "A"); + B.allocate(pb, new_num_constraints, "B"); + + inner_product_gadget compute_inner_product(pb, A, B, res, "compute_inner_product"); + compute_inner_product.generate_r1cs_constraints(); + + /* fill in random example */ + for (size_t i = 0; i < new_num_constraints; ++i) + { + pb.val(A[i]) = FieldT::random_element(); + pb.val(B[i]) = FieldT::random_element(); + } + + compute_inner_product.generate_r1cs_witness(); + return r1cs_example(pb.get_constraint_system(), pb.primary_input(), pb.auxiliary_input()); +} + +} // libsnark +#endif // R1CS_EXAMPLES_TCC_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadget.hpp b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadget.hpp new file mode 100644 index 0000000..dbeaa9d --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadget.hpp @@ -0,0 +1,27 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef GADGET_HPP_ +#define GADGET_HPP_ + +#include "gadgetlib1/protoboard.hpp" + +namespace libsnark { + +template +class gadget { +protected: + protoboard &pb; + const std::string annotation_prefix; +public: + gadget(protoboard &pb, const std::string &annotation_prefix=""); +}; + +} // libsnark +#include "gadgetlib1/gadget.tcc" + +#endif // GADGET_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadget.tcc b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadget.tcc new file mode 100644 index 0000000..120229b --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadget.tcc @@ -0,0 +1,23 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef GADGET_TCC_ +#define GADGET_TCC_ + +namespace libsnark { + +template +gadget::gadget(protoboard &pb, const std::string &annotation_prefix) : + pb(pb), annotation_prefix(annotation_prefix) +{ +#ifdef DEBUG + assert(annotation_prefix != ""); +#endif +} + +} // libsnark +#endif // GADGET_TCC_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/basic_gadgets.hpp b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/basic_gadgets.hpp new file mode 100644 index 0000000..08e596b --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/basic_gadgets.hpp @@ -0,0 +1,351 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef BASIC_GADGETS_HPP_ +#define BASIC_GADGETS_HPP_ + +#include +#include + +#include "gadgetlib1/gadget.hpp" + +namespace libsnark { + +/* forces lc to take value 0 or 1 by adding constraint lc * (1-lc) = 0 */ +template +void generate_boolean_r1cs_constraint(protoboard &pb, const pb_linear_combination &lc, const std::string &annotation_prefix=""); + +template +void generate_r1cs_equals_const_constraint(protoboard &pb, const pb_linear_combination &lc, const FieldT& c, const std::string &annotation_prefix=""); + +template +class packing_gadget : public gadget { +private: + /* no internal variables */ +public: + const pb_linear_combination_array bits; + const pb_linear_combination packed; + + packing_gadget(protoboard &pb, + const pb_linear_combination_array &bits, + const pb_linear_combination &packed, + const std::string &annotation_prefix="") : + gadget(pb, annotation_prefix), bits(bits), packed(packed) {} + + void generate_r1cs_constraints(const bool enforce_bitness); + /* adds constraint result = \sum bits[i] * 2^i */ + + void generate_r1cs_witness_from_packed(); + void generate_r1cs_witness_from_bits(); +}; + +template +class multipacking_gadget : public gadget { +private: + std::vector > packers; +public: + const pb_linear_combination_array bits; + const pb_linear_combination_array packed_vars; + + const size_t chunk_size; + const size_t num_chunks; + // const size_t last_chunk_size; + + multipacking_gadget(protoboard &pb, + const pb_linear_combination_array &bits, + const pb_linear_combination_array &packed_vars, + const size_t chunk_size, + const std::string &annotation_prefix=""); + void generate_r1cs_constraints(const bool enforce_bitness); + void generate_r1cs_witness_from_packed(); + void generate_r1cs_witness_from_bits(); +}; + +template +class field_vector_copy_gadget : public gadget { +public: + const pb_variable_array source; + const pb_variable_array target; + const pb_linear_combination do_copy; + + field_vector_copy_gadget(protoboard &pb, + const pb_variable_array &source, + const pb_variable_array &target, + const pb_linear_combination &do_copy, + const std::string &annotation_prefix=""); + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +template +class bit_vector_copy_gadget : public gadget { +public: + const pb_variable_array source_bits; + const pb_variable_array target_bits; + const pb_linear_combination do_copy; + + pb_variable_array packed_source; + pb_variable_array packed_target; + + std::shared_ptr > pack_source; + std::shared_ptr > pack_target; + std::shared_ptr > copier; + + const size_t chunk_size; + const size_t num_chunks; + + bit_vector_copy_gadget(protoboard &pb, + const pb_variable_array &source_bits, + const pb_variable_array &target_bits, + const pb_linear_combination &do_copy, + const size_t chunk_size, + const std::string &annotation_prefix=""); + void generate_r1cs_constraints(const bool enforce_source_bitness, const bool enforce_target_bitness); + void generate_r1cs_witness(); +}; + +template +class dual_variable_gadget : public gadget { +private: + std::shared_ptr > consistency_check; +public: + pb_variable packed; + pb_variable_array bits; + + dual_variable_gadget(protoboard &pb, + const size_t width, + const std::string &annotation_prefix="") : + gadget(pb, annotation_prefix) + { + packed.allocate(pb, FMT(this->annotation_prefix, " packed")); + bits.allocate(pb, width, FMT(this->annotation_prefix, " bits")); + consistency_check.reset(new packing_gadget(pb, + bits, + packed, + FMT(this->annotation_prefix, " consistency_check"))); + } + + dual_variable_gadget(protoboard &pb, + const pb_variable_array &bits, + const std::string &annotation_prefix="") : + gadget(pb, annotation_prefix), bits(bits) + { + packed.allocate(pb, FMT(this->annotation_prefix, " packed")); + consistency_check.reset(new packing_gadget(pb, + bits, + packed, + FMT(this->annotation_prefix, " consistency_check"))); + } + + dual_variable_gadget(protoboard &pb, + const pb_variable &packed, + const size_t width, + const std::string &annotation_prefix="") : + gadget(pb, annotation_prefix), packed(packed) + { + bits.allocate(pb, width, FMT(this->annotation_prefix, " bits")); + consistency_check.reset(new packing_gadget(pb, + bits, + packed, + FMT(this->annotation_prefix, " consistency_check"))); + } + + void generate_r1cs_constraints(const bool enforce_bitness); + void generate_r1cs_witness_from_packed(); + void generate_r1cs_witness_from_bits(); +}; + +/* + the gadgets below are Fp specific: + I * X = R + (1-R) * X = 0 + + if X = 0 then R = 0 + if X != 0 then R = 1 and I = X^{-1} +*/ + +template +class disjunction_gadget : public gadget { +private: + pb_variable inv; +public: + const pb_variable_array inputs; + const pb_variable output; + + disjunction_gadget(protoboard& pb, + const pb_variable_array &inputs, + const pb_variable &output, + const std::string &annotation_prefix="") : + gadget(pb, annotation_prefix), inputs(inputs), output(output) + { + assert(inputs.size() >= 1); + inv.allocate(pb, FMT(this->annotation_prefix, " inv")); + } + + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +template +void test_disjunction_gadget(const size_t n); + +template +class conjunction_gadget : public gadget { +private: + pb_variable inv; +public: + const pb_variable_array inputs; + const pb_variable output; + + conjunction_gadget(protoboard& pb, + const pb_variable_array &inputs, + const pb_variable &output, + const std::string &annotation_prefix="") : + gadget(pb, annotation_prefix), inputs(inputs), output(output) + { + assert(inputs.size() >= 1); + inv.allocate(pb, FMT(this->annotation_prefix, " inv")); + } + + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +template +void test_conjunction_gadget(const size_t n); + +template +class comparison_gadget : public gadget { +private: + pb_variable_array alpha; + pb_variable alpha_packed; + std::shared_ptr > pack_alpha; + + std::shared_ptr > all_zeros_test; + pb_variable not_all_zeros; +public: + const size_t n; + const pb_linear_combination A; + const pb_linear_combination B; + const pb_variable less; + const pb_variable less_or_eq; + + comparison_gadget(protoboard& pb, + const size_t n, + const pb_linear_combination &A, + const pb_linear_combination &B, + const pb_variable &less, + const pb_variable &less_or_eq, + const std::string &annotation_prefix="") : + gadget(pb, annotation_prefix), n(n), A(A), B(B), less(less), less_or_eq(less_or_eq) + { + alpha.allocate(pb, n, FMT(this->annotation_prefix, " alpha")); + alpha.emplace_back(less_or_eq); // alpha[n] is less_or_eq + + alpha_packed.allocate(pb, FMT(this->annotation_prefix, " alpha_packed")); + not_all_zeros.allocate(pb, FMT(this->annotation_prefix, " not_all_zeros")); + + pack_alpha.reset(new packing_gadget(pb, alpha, alpha_packed, + FMT(this->annotation_prefix, " pack_alpha"))); + + all_zeros_test.reset(new disjunction_gadget(pb, + pb_variable_array(alpha.begin(), alpha.begin() + n), + not_all_zeros, + FMT(this->annotation_prefix, " all_zeros_test"))); + }; + + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +template +void test_comparison_gadget(const size_t n); + +template +class inner_product_gadget : public gadget { +private: + /* S_i = \sum_{k=0}^{i+1} A[i] * B[i] */ + pb_variable_array S; +public: + const pb_linear_combination_array A; + const pb_linear_combination_array B; + const pb_variable result; + + inner_product_gadget(protoboard& pb, + const pb_linear_combination_array &A, + const pb_linear_combination_array &B, + const pb_variable &result, + const std::string &annotation_prefix="") : + gadget(pb, annotation_prefix), A(A), B(B), result(result) + { + assert(A.size() >= 1); + assert(A.size() == B.size()); + + S.allocate(pb, A.size()-1, FMT(this->annotation_prefix, " S")); + } + + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +template +void test_inner_product_gadget(const size_t n); + +template +class loose_multiplexing_gadget : public gadget { +/* + this implements loose multiplexer: + index not in bounds -> success_flag = 0 + index in bounds && success_flag = 1 -> result is correct + however if index is in bounds we can also set success_flag to 0 (and then result will be forced to be 0) +*/ +public: + pb_variable_array alpha; +private: + std::shared_ptr > compute_result; +public: + const pb_linear_combination_array arr; + const pb_variable index; + const pb_variable result; + const pb_variable success_flag; + + loose_multiplexing_gadget(protoboard& pb, + const pb_linear_combination_array &arr, + const pb_variable &index, + const pb_variable &result, + const pb_variable &success_flag, + const std::string &annotation_prefix="") : + gadget(pb, annotation_prefix), arr(arr), index(index), result(result), success_flag(success_flag) + { + alpha.allocate(pb, arr.size(), FMT(this->annotation_prefix, " alpha")); + compute_result.reset(new inner_product_gadget(pb, alpha, arr, result, FMT(this->annotation_prefix, " compute_result"))); + }; + + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +template +void test_loose_multiplexing_gadget(const size_t n); + +template +void create_linear_combination_constraints(protoboard &pb, + const std::vector &base, + const std::vector > &v, + const VarT &target, + const std::string &annotation_prefix); + +template +void create_linear_combination_witness(protoboard &pb, + const std::vector &base, + const std::vector > &v, + const VarT &target); + +} // libsnark +#include "gadgetlib1/gadgets/basic_gadgets.tcc" + +#endif // BASIC_GADGETS_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/basic_gadgets.tcc b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/basic_gadgets.tcc new file mode 100644 index 0000000..45fd7aa --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/basic_gadgets.tcc @@ -0,0 +1,705 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef BASIC_GADGETS_TCC_ +#define BASIC_GADGETS_TCC_ + +#include "common/profiling.hpp" +#include "common/utils.hpp" + +namespace libsnark { + +template +void generate_boolean_r1cs_constraint(protoboard &pb, const pb_linear_combination &lc, const std::string &annotation_prefix) +/* forces lc to take value 0 or 1 by adding constraint lc * (1-lc) = 0 */ +{ + pb.add_r1cs_constraint(r1cs_constraint(lc, 1-lc, 0), + FMT(annotation_prefix, " boolean_r1cs_constraint")); +} + +template +void generate_r1cs_equals_const_constraint(protoboard &pb, const pb_linear_combination &lc, const FieldT& c, const std::string &annotation_prefix) +{ + pb.add_r1cs_constraint(r1cs_constraint(1, lc, c), + FMT(annotation_prefix, " constness_constraint")); +} + +template +void packing_gadget::generate_r1cs_constraints(const bool enforce_bitness) +/* adds constraint result = \sum bits[i] * 2^i */ +{ + this->pb.add_r1cs_constraint(r1cs_constraint(1, pb_packing_sum(bits), packed), FMT(this->annotation_prefix, " packing_constraint")); + + if (enforce_bitness) + { + for (size_t i = 0; i < bits.size(); ++i) + { + generate_boolean_r1cs_constraint(this->pb, bits[i], FMT(this->annotation_prefix, " bitness_%zu", i)); + } + } +} + +template +void packing_gadget::generate_r1cs_witness_from_packed() +{ + packed.evaluate(this->pb); + assert(this->pb.lc_val(packed).as_bigint().num_bits() <= bits.size()); // `bits` is large enough to represent this packed value + bits.fill_with_bits_of_field_element(this->pb, this->pb.lc_val(packed)); +} + +template +void packing_gadget::generate_r1cs_witness_from_bits() +{ + bits.evaluate(this->pb); + this->pb.lc_val(packed) = bits.get_field_element_from_bits(this->pb); +} + +template +multipacking_gadget::multipacking_gadget(protoboard &pb, + const pb_linear_combination_array &bits, + const pb_linear_combination_array &packed_vars, + const size_t chunk_size, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), bits(bits), packed_vars(packed_vars), + chunk_size(chunk_size), + num_chunks(div_ceil(bits.size(), chunk_size)) + // last_chunk_size(bits.size() - (num_chunks-1) * chunk_size) +{ + assert(packed_vars.size() == num_chunks); + for (size_t i = 0; i < num_chunks; ++i) + { + packers.emplace_back(packing_gadget(this->pb, pb_linear_combination_array(bits.begin() + i * chunk_size, + bits.begin() + std::min((i+1) * chunk_size, bits.size())), + packed_vars[i], FMT(this->annotation_prefix, " packers_%zu", i))); + } +} + +template +void multipacking_gadget::generate_r1cs_constraints(const bool enforce_bitness) +{ + for (size_t i = 0; i < num_chunks; ++i) + { + packers[i].generate_r1cs_constraints(enforce_bitness); + } +} + +template +void multipacking_gadget::generate_r1cs_witness_from_packed() +{ + for (size_t i = 0; i < num_chunks; ++i) + { + packers[i].generate_r1cs_witness_from_packed(); + } +} + +template +void multipacking_gadget::generate_r1cs_witness_from_bits() +{ + for (size_t i = 0; i < num_chunks; ++i) + { + packers[i].generate_r1cs_witness_from_bits(); + } +} + +template +size_t multipacking_num_chunks(const size_t num_bits) +{ + return div_ceil(num_bits, FieldT::capacity()); +} + +template +field_vector_copy_gadget::field_vector_copy_gadget(protoboard &pb, + const pb_variable_array &source, + const pb_variable_array &target, + const pb_linear_combination &do_copy, + const std::string &annotation_prefix) : +gadget(pb, annotation_prefix), source(source), target(target), do_copy(do_copy) +{ + assert(source.size() == target.size()); +} + +template +void field_vector_copy_gadget::generate_r1cs_constraints() +{ + for (size_t i = 0; i < source.size(); ++i) + { + this->pb.add_r1cs_constraint(r1cs_constraint(do_copy, source[i] - target[i], 0), + FMT(this->annotation_prefix, " copying_check_%zu", i)); + } +} + +template +void field_vector_copy_gadget::generate_r1cs_witness() +{ + do_copy.evaluate(this->pb); + assert(this->pb.lc_val(do_copy) == FieldT::one() || this->pb.lc_val(do_copy) == FieldT::zero()); + if (this->pb.lc_val(do_copy) != FieldT::zero()) + { + for (size_t i = 0; i < source.size(); ++i) + { + this->pb.val(target[i]) = this->pb.val(source[i]); + } + } +} + +template +bit_vector_copy_gadget::bit_vector_copy_gadget(protoboard &pb, + const pb_variable_array &source_bits, + const pb_variable_array &target_bits, + const pb_linear_combination &do_copy, + const size_t chunk_size, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), source_bits(source_bits), target_bits(target_bits), do_copy(do_copy), + chunk_size(chunk_size), num_chunks(div_ceil(source_bits.size(), chunk_size)) +{ + assert(source_bits.size() == target_bits.size()); + + packed_source.allocate(pb, num_chunks, FMT(annotation_prefix, " packed_source")); + pack_source.reset(new multipacking_gadget(pb, source_bits, packed_source, chunk_size, FMT(annotation_prefix, " pack_source"))); + + packed_target.allocate(pb, num_chunks, FMT(annotation_prefix, " packed_target")); + pack_target.reset(new multipacking_gadget(pb, target_bits, packed_target, chunk_size, FMT(annotation_prefix, " pack_target"))); + + copier.reset(new field_vector_copy_gadget(pb, packed_source, packed_target, do_copy, FMT(annotation_prefix, " copier"))); +} + +template +void bit_vector_copy_gadget::generate_r1cs_constraints(const bool enforce_source_bitness, const bool enforce_target_bitness) +{ + pack_source->generate_r1cs_constraints(enforce_source_bitness); + pack_target->generate_r1cs_constraints(enforce_target_bitness); + + copier->generate_r1cs_constraints(); +} + +template +void bit_vector_copy_gadget::generate_r1cs_witness() +{ + do_copy.evaluate(this->pb); + assert(this->pb.lc_val(do_copy) == FieldT::zero() || this->pb.lc_val(do_copy) == FieldT::one()); + if (this->pb.lc_val(do_copy) == FieldT::one()) + { + for (size_t i = 0; i < source_bits.size(); ++i) + { + this->pb.val(target_bits[i]) = this->pb.val(source_bits[i]); + } + } + + pack_source->generate_r1cs_witness_from_bits(); + pack_target->generate_r1cs_witness_from_bits(); +} + +template +void dual_variable_gadget::generate_r1cs_constraints(const bool enforce_bitness) +{ + consistency_check->generate_r1cs_constraints(enforce_bitness); +} + +template +void dual_variable_gadget::generate_r1cs_witness_from_packed() +{ + consistency_check->generate_r1cs_witness_from_packed(); +} + +template +void dual_variable_gadget::generate_r1cs_witness_from_bits() +{ + consistency_check->generate_r1cs_witness_from_bits(); +} + +template +void disjunction_gadget::generate_r1cs_constraints() +{ + /* inv * sum = output */ + linear_combination a1, b1, c1; + a1.add_term(inv); + for (size_t i = 0; i < inputs.size(); ++i) + { + b1.add_term(inputs[i]); + } + c1.add_term(output); + + this->pb.add_r1cs_constraint(r1cs_constraint(a1, b1, c1), FMT(this->annotation_prefix, " inv*sum=output")); + + /* (1-output) * sum = 0 */ + linear_combination a2, b2, c2; + a2.add_term(ONE); + a2.add_term(output, -1); + for (size_t i = 0; i < inputs.size(); ++i) + { + b2.add_term(inputs[i]); + } + c2.add_term(ONE, 0); + + this->pb.add_r1cs_constraint(r1cs_constraint(a2, b2, c2), FMT(this->annotation_prefix, " (1-output)*sum=0")); +} + +template +void disjunction_gadget::generate_r1cs_witness() +{ + FieldT sum = FieldT::zero(); + + for (size_t i = 0; i < inputs.size(); ++i) + { + sum += this->pb.val(inputs[i]); + } + + if (sum.is_zero()) + { + this->pb.val(inv) = FieldT::zero(); + this->pb.val(output) = FieldT::zero(); + } + else + { + this->pb.val(inv) = sum.inverse(); + this->pb.val(output) = FieldT::one(); + } +} + +template +void test_disjunction_gadget(const size_t n) +{ + printf("testing disjunction_gadget on all %zu bit strings\n", n); + + protoboard pb; + pb_variable_array inputs; + inputs.allocate(pb, n, "inputs"); + + pb_variable output; + output.allocate(pb, "output"); + + disjunction_gadget d(pb, inputs, output, "d"); + d.generate_r1cs_constraints(); + + for (size_t w = 0; w < 1ul< +void conjunction_gadget::generate_r1cs_constraints() +{ + /* inv * (n-sum) = 1-output */ + linear_combination a1, b1, c1; + a1.add_term(inv); + b1.add_term(ONE, inputs.size()); + for (size_t i = 0; i < inputs.size(); ++i) + { + b1.add_term(inputs[i], -1); + } + c1.add_term(ONE); + c1.add_term(output, -1); + + this->pb.add_r1cs_constraint(r1cs_constraint(a1, b1, c1), FMT(this->annotation_prefix, " inv*(n-sum)=(1-output)")); + + /* output * (n-sum) = 0 */ + linear_combination a2, b2, c2; + a2.add_term(output); + b2.add_term(ONE, inputs.size()); + for (size_t i = 0; i < inputs.size(); ++i) + { + b2.add_term(inputs[i], -1); + } + c2.add_term(ONE, 0); + + this->pb.add_r1cs_constraint(r1cs_constraint(a2, b2, c2), FMT(this->annotation_prefix, " output*(n-sum)=0")); +} + +template +void conjunction_gadget::generate_r1cs_witness() +{ + FieldT sum = FieldT(inputs.size()); + + for (size_t i = 0; i < inputs.size(); ++i) + { + sum -= this->pb.val(inputs[i]); + } + + if (sum.is_zero()) + { + this->pb.val(inv) = FieldT::zero(); + this->pb.val(output) = FieldT::one(); + } + else + { + this->pb.val(inv) = sum.inverse(); + this->pb.val(output) = FieldT::zero(); + } +} + +template +void test_conjunction_gadget(const size_t n) +{ + printf("testing conjunction_gadget on all %zu bit strings\n", n); + + protoboard pb; + pb_variable_array inputs; + inputs.allocate(pb, n, "inputs"); + + pb_variable output; + output.allocate(pb, "output"); + + conjunction_gadget c(pb, inputs, output, "c"); + c.generate_r1cs_constraints(); + + for (size_t w = 0; w < 1ul< +void comparison_gadget::generate_r1cs_constraints() +{ + /* + packed(alpha) = 2^n + B - A + + not_all_zeros = \bigvee_{i=0}^{n-1} alpha_i + + if B - A > 0, then 2^n + B - A > 2^n, + so alpha_n = 1 and not_all_zeros = 1 + if B - A = 0, then 2^n + B - A = 2^n, + so alpha_n = 1 and not_all_zeros = 0 + if B - A < 0, then 2^n + B - A \in {0, 1, \ldots, 2^n-1}, + so alpha_n = 0 + + therefore alpha_n = less_or_eq and alpha_n * not_all_zeros = less + */ + + /* not_all_zeros to be Boolean, alpha_i are Boolean by packing gadget */ + generate_boolean_r1cs_constraint(this->pb, not_all_zeros, + FMT(this->annotation_prefix, " not_all_zeros")); + + /* constraints for packed(alpha) = 2^n + B - A */ + pack_alpha->generate_r1cs_constraints(true); + this->pb.add_r1cs_constraint(r1cs_constraint(1, (FieldT(2)^n) + B - A, alpha_packed), FMT(this->annotation_prefix, " main_constraint")); + + /* compute result */ + all_zeros_test->generate_r1cs_constraints(); + this->pb.add_r1cs_constraint(r1cs_constraint(less_or_eq, not_all_zeros, less), + FMT(this->annotation_prefix, " less")); +} + +template +void comparison_gadget::generate_r1cs_witness() +{ + A.evaluate(this->pb); + B.evaluate(this->pb); + + /* unpack 2^n + B - A into alpha_packed */ + this->pb.val(alpha_packed) = (FieldT(2)^n) + this->pb.lc_val(B) - this->pb.lc_val(A); + pack_alpha->generate_r1cs_witness_from_packed(); + + /* compute result */ + all_zeros_test->generate_r1cs_witness(); + this->pb.val(less) = this->pb.val(less_or_eq) * this->pb.val(not_all_zeros); +} + +template +void test_comparison_gadget(const size_t n) +{ + printf("testing comparison_gadget on all %zu bit inputs\n", n); + + protoboard pb; + + pb_variable A, B, less, less_or_eq; + A.allocate(pb, "A"); + B.allocate(pb, "B"); + less.allocate(pb, "less"); + less_or_eq.allocate(pb, "less_or_eq"); + + comparison_gadget cmp(pb, n, A, B, less, less_or_eq, "cmp"); + cmp.generate_r1cs_constraints(); + + for (size_t a = 0; a < 1ul< +void inner_product_gadget::generate_r1cs_constraints() +{ + /* + S_i = \sum_{k=0}^{i+1} A[i] * B[i] + S[0] = A[0] * B[0] + S[i+1] - S[i] = A[i] * B[i] + */ + for (size_t i = 0; i < A.size(); ++i) + { + this->pb.add_r1cs_constraint( + r1cs_constraint(A[i], B[i], + (i == A.size()-1 ? result : S[i]) + (i == 0 ? 0 * ONE : -S[i-1])), + FMT(this->annotation_prefix, " S_%zu", i)); + } +} + +template +void inner_product_gadget::generate_r1cs_witness() +{ + FieldT total = FieldT::zero(); + for (size_t i = 0; i < A.size(); ++i) + { + A[i].evaluate(this->pb); + B[i].evaluate(this->pb); + + total += this->pb.lc_val(A[i]) * this->pb.lc_val(B[i]); + this->pb.val(i == A.size()-1 ? result : S[i]) = total; + } +} + +template +void test_inner_product_gadget(const size_t n) +{ + printf("testing inner_product_gadget on all %zu bit strings\n", n); + + protoboard pb; + pb_variable_array A; + A.allocate(pb, n, "A"); + pb_variable_array B; + B.allocate(pb, n, "B"); + + pb_variable result; + result.allocate(pb, "result"); + + inner_product_gadget g(pb, A, B, result, "g"); + g.generate_r1cs_constraints(); + + for (size_t i = 0; i < 1ul< +void loose_multiplexing_gadget::generate_r1cs_constraints() +{ + /* \alpha_i (index - i) = 0 */ + for (size_t i = 0; i < arr.size(); ++i) + { + this->pb.add_r1cs_constraint( + r1cs_constraint(alpha[i], index - i, 0), + FMT(this->annotation_prefix, " alpha_%zu", i)); + } + + /* 1 * (\sum \alpha_i) = success_flag */ + linear_combination a, b, c; + a.add_term(ONE); + for (size_t i = 0; i < arr.size(); ++i) + { + b.add_term(alpha[i]); + } + c.add_term(success_flag); + this->pb.add_r1cs_constraint(r1cs_constraint(a, b, c), FMT(this->annotation_prefix, " main_constraint")); + + /* now success_flag is constrained to either 0 (if index is out of + range) or \alpha_i. constrain it and \alpha_i to zero */ + generate_boolean_r1cs_constraint(this->pb, success_flag, FMT(this->annotation_prefix, " success_flag")); + + /* compute result */ + compute_result->generate_r1cs_constraints(); +} + +template +void loose_multiplexing_gadget::generate_r1cs_witness() +{ + /* assumes that idx can be fit in ulong; true for our purposes for now */ + const bigint valint = this->pb.val(index).as_bigint(); + unsigned long idx = valint.as_ulong(); + const bigint arrsize(arr.size()); + + if (idx >= arr.size() || mpn_cmp(valint.data, arrsize.data, FieldT::num_limbs) >= 0) + { + for (size_t i = 0; i < arr.size(); ++i) + { + this->pb.val(alpha[i]) = FieldT::zero(); + } + + this->pb.val(success_flag) = FieldT::zero(); + } + else + { + for (size_t i = 0; i < arr.size(); ++i) + { + this->pb.val(alpha[i]) = (i == idx ? FieldT::one() : FieldT::zero()); + } + + this->pb.val(success_flag) = FieldT::one(); + } + + compute_result->generate_r1cs_witness(); +} + +template +void test_loose_multiplexing_gadget(const size_t n) +{ + printf("testing loose_multiplexing_gadget on 2**%zu pb_variable array inputs\n", n); + protoboard pb; + + pb_variable_array arr; + arr.allocate(pb, 1ul< index, result, success_flag; + index.allocate(pb, "index"); + result.allocate(pb, "result"); + success_flag.allocate(pb, "success_flag"); + + loose_multiplexing_gadget g(pb, arr, index, result, success_flag, "g"); + g.generate_r1cs_constraints(); + + for (size_t i = 0; i < 1ul< +void create_linear_combination_constraints(protoboard &pb, + const std::vector &base, + const std::vector > &v, + const VarT &target, + const std::string &annotation_prefix) +{ + for (size_t i = 0; i < base.size(); ++i) + { + linear_combination a, b, c; + + a.add_term(ONE); + b.add_term(ONE, base[i]); + + for (auto &p : v) + { + b.add_term(p.first.all_vars[i], p.second); + } + + c.add_term(target.all_vars[i]); + + pb.add_r1cs_constraint(r1cs_constraint(a, b, c), FMT(annotation_prefix, " linear_combination_%zu", i)); + } +} + +template +void create_linear_combination_witness(protoboard &pb, + const std::vector &base, + const std::vector > &v, + const VarT &target) +{ + for (size_t i = 0; i < base.size(); ++i) + { + pb.val(target.all_vars[i]) = base[i]; + + for (auto &p : v) + { + pb.val(target.all_vars[i]) += p.second * pb.val(p.first.all_vars[i]); + } + } +} + +} // libsnark +#endif // BASIC_GADGETS_TCC_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/cpu_checkers/fooram/components/bar_gadget.hpp b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/cpu_checkers/fooram/components/bar_gadget.hpp new file mode 100644 index 0000000..0e28032 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/cpu_checkers/fooram/components/bar_gadget.hpp @@ -0,0 +1,64 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for an auxiliarry gadget for the FOORAM CPU. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef BAR_GADGET_HPP_ +#define BAR_GADGET_HPP_ + +#include "gadgetlib1/gadget.hpp" +#include "gadgetlib1/gadgets/basic_gadgets.hpp" + +namespace libsnark { + +/** + * The bar gadget checks linear combination + * Z = aX + bY (mod 2^w) + * for a, b - const, X, Y - vectors of w bits, + * where w is implicitly inferred, Z - a packed variable. + * + * This gadget is used four times in fooram: + * - PC' = PC + 1 + * - load_addr = 2 * x + PC' + * - store_addr = x + PC + */ +template +class bar_gadget : public gadget { +public: + pb_linear_combination_array X; + FieldT a; + pb_linear_combination_array Y; + FieldT b; + pb_linear_combination Z_packed; + pb_variable_array Z_bits; + + pb_variable result; + pb_variable_array overflow; + pb_variable_array unpacked_result; + + std::shared_ptr > unpack_result; + std::shared_ptr > pack_Z; + + size_t width; + bar_gadget(protoboard &pb, + const pb_linear_combination_array &X, + const FieldT &a, + const pb_linear_combination_array &Y, + const FieldT &b, + const pb_linear_combination &Z_packed, + const std::string &annotation_prefix); + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +} // libsnark + +#include "gadgetlib1/gadgets/cpu_checkers/fooram/components/bar_gadget.tcc" + +#endif // BAR_GADGET_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/cpu_checkers/fooram/components/bar_gadget.tcc b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/cpu_checkers/fooram/components/bar_gadget.tcc new file mode 100644 index 0000000..f25d1df --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/cpu_checkers/fooram/components/bar_gadget.tcc @@ -0,0 +1,68 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for an auxiliarry gadget for the FOORAM CPU. + + See bar_gadget.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef BAR_GADGET_TCC_ +#define BAR_GADGET_TCC_ + +namespace libsnark { + +template +bar_gadget::bar_gadget(protoboard &pb, + const pb_linear_combination_array &X, + const FieldT &a, + const pb_linear_combination_array &Y, + const FieldT &b, + const pb_linear_combination &Z_packed, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), + X(X), + a(a), + Y(Y), + b(b), + Z_packed(Z_packed) +{ + assert(X.size() == Y.size()); + width = X.size(); + + result.allocate(pb, FMT(annotation_prefix, " result")); + Z_bits.allocate(pb, width, FMT(annotation_prefix, " Z_bits")); + overflow.allocate(pb, 2*width, FMT(annotation_prefix, " overflow")); + + unpacked_result.insert(unpacked_result.end(), Z_bits.begin(), Z_bits.end()); + unpacked_result.insert(unpacked_result.end(), overflow.begin(), overflow.end()); + + unpack_result.reset(new packing_gadget(pb, unpacked_result, result, FMT(annotation_prefix, " unpack_result"))); + pack_Z.reset(new packing_gadget(pb, Z_bits, Z_packed, FMT(annotation_prefix, " pack_Z"))); +} + +template +void bar_gadget::generate_r1cs_constraints() +{ + unpack_result->generate_r1cs_constraints(true); + pack_Z->generate_r1cs_constraints(false); + + this->pb.add_r1cs_constraint(r1cs_constraint(1, a * pb_packing_sum(X) + b * pb_packing_sum(Y), result), FMT(this->annotation_prefix, " compute_result")); +} + +template +void bar_gadget::generate_r1cs_witness() +{ + this->pb.val(result) = X.get_field_element_from_bits(this->pb) * a + Y.get_field_element_from_bits(this->pb) * b; + unpack_result->generate_r1cs_witness_from_packed(); + + pack_Z->generate_r1cs_witness_from_bits(); +} + +} // libsnark + +#endif // BAR_GADGET_TCC_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/cpu_checkers/fooram/components/fooram_protoboard.hpp b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/cpu_checkers/fooram/components/fooram_protoboard.hpp new file mode 100644 index 0000000..d8c3ca8 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/cpu_checkers/fooram/components/fooram_protoboard.hpp @@ -0,0 +1,40 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for a protoboard for the FOORAM CPU. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef FOORAM_PROTOBOARD_HPP_ +#define FOORAM_PROTOBOARD_HPP_ + +#include "gadgetlib1/gadget.hpp" +#include "relations/ram_computations/rams/fooram/fooram_aux.hpp" + +namespace libsnark { + +template +class fooram_protoboard : public protoboard { +public: + const fooram_architecture_params ap; + + fooram_protoboard(const fooram_architecture_params &ap); +}; + +template +class fooram_gadget : public gadget { +protected: + fooram_protoboard &pb; +public: + fooram_gadget(fooram_protoboard &pb, const std::string &annotation_prefix=""); +}; + +} // libsnark + +#include "gadgetlib1/gadgets/cpu_checkers/fooram/components/fooram_protoboard.tcc" + +#endif // FOORAM_PROTOBOARD_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/cpu_checkers/fooram/components/fooram_protoboard.tcc b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/cpu_checkers/fooram/components/fooram_protoboard.tcc new file mode 100644 index 0000000..035cfab --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/cpu_checkers/fooram/components/fooram_protoboard.tcc @@ -0,0 +1,33 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for a protoboard for the FOORAM CPU. + + See fooram_protoboard.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef FOORAM_PROTOBOARD_TCC_ +#define FOORAM_PROTOBOARD_TCC_ + +namespace libsnark { + +template +fooram_protoboard::fooram_protoboard(const fooram_architecture_params &ap) : + protoboard(), ap(ap) +{ +} + +template +fooram_gadget::fooram_gadget(fooram_protoboard &pb, const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), pb(pb) +{ +} + +} // libsnark + +#endif // FOORAM_PROTOBOARD_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/cpu_checkers/fooram/examples/test_fooram.cpp b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/cpu_checkers/fooram/examples/test_fooram.cpp new file mode 100644 index 0000000..347ba03 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/cpu_checkers/fooram/examples/test_fooram.cpp @@ -0,0 +1,82 @@ +/** + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ +#include "common/default_types/r1cs_ppzksnark_pp.hpp" +#include "common/default_types/r1cs_ppzkpcd_pp.hpp" +#include "common/utils.hpp" +#include "zk_proof_systems/zksnark/ram_zksnark/examples/run_ram_zksnark.hpp" +#include "zk_proof_systems/ppzksnark/ram_ppzksnark/examples/run_ram_ppzksnark.hpp" + +#include "relations/ram_computations/rams/fooram/fooram_params.hpp" + +namespace libsnark { + +class default_fooram_zksnark_pp { +public: + typedef default_r1cs_ppzkpcd_pp PCD_pp; + typedef typename PCD_pp::scalar_field_A FieldT; + typedef ram_fooram machine_pp; + + static void init_public_params() { PCD_pp::init_public_params(); } +}; + +class default_fooram_ppzksnark_pp { +public: + typedef default_r1cs_ppzksnark_pp snark_pp; + typedef Fr FieldT; + typedef ram_fooram machine_pp; + + static void init_public_params() { snark_pp::init_public_params(); } +}; + +} // libsnark + +using namespace libsnark; + +template +void profile_ram_zksnark(const size_t w) +{ + typedef ram_zksnark_machine_pp ramT; + + ram_example example; + example.ap = ram_architecture_params(w); + example.boot_trace_size_bound = 0; + example.time_bound = 10; + const bool test_serialization = true; + const bool bit = run_ram_zksnark(example, test_serialization); + assert(bit); +} + +template +void profile_ram_ppzksnark(const size_t w) +{ + typedef ram_ppzksnark_machine_pp ramT; + + ram_example example; + example.ap = ram_architecture_params(w); + example.boot_trace_size_bound = 0; + example.time_bound = 100; + const bool test_serialization = true; + const bool bit = run_ram_ppzksnark(example, test_serialization); + assert(bit); +} + +int main(int argc, const char* argv[]) +{ + UNUSED(argv); + start_profiling(); + default_fooram_ppzksnark_pp::init_public_params(); + default_fooram_zksnark_pp::init_public_params(); + + if (argc == 1) + { + profile_ram_zksnark(32); + } + else + { + profile_ram_ppzksnark(8); + } +} diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/cpu_checkers/fooram/fooram_cpu_checker.hpp b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/cpu_checkers/fooram/fooram_cpu_checker.hpp new file mode 100644 index 0000000..d12198f --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/cpu_checkers/fooram/fooram_cpu_checker.hpp @@ -0,0 +1,107 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for the FOORAM CPU checker gadget. + + The gadget checks the correct operation for the CPU of the FOORAM architecture. + + In FOORAM, the only instruction is FOO(x) and its encoding is x. + The instruction FOO(x) has the following semantics: + - if x is odd: reg <- [2*x+(pc+1)] + - if x is even: [pc+x] <- reg+pc + - increment pc by 1 + + Starting from empty memory, FOORAM performs non-trivial pseudo-random computation + that exercises both loads, stores, and instruction fetches. + + E.g. for the first 200 steps on 16 cell machine we get 93 different memory configurations. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef FOORAM_CPU_CHECKER_HPP_ +#define FOORAM_CPU_CHECKER_HPP_ + +#include +#include + +#include "common/serialization.hpp" +#include "gadgetlib1/gadget.hpp" +#include "gadgetlib1/gadgets/basic_gadgets.hpp" +#include "gadgetlib1/gadgets/cpu_checkers/fooram/components/fooram_protoboard.hpp" +#include "gadgetlib1/gadgets/cpu_checkers/fooram/components/bar_gadget.hpp" +#include "relations/ram_computations/memory/memory_interface.hpp" + +namespace libsnark { + +template +class fooram_cpu_checker : public fooram_gadget { +public: + pb_variable_array prev_pc_addr; + pb_variable_array prev_pc_val; + pb_variable_array prev_state; + pb_variable_array guess; + pb_variable_array ls_addr; + pb_variable_array ls_prev_val; + pb_variable_array ls_next_val; + pb_variable_array next_state; + pb_variable_array next_pc_addr; + pb_variable next_has_accepted; + + pb_variable zero; + pb_variable packed_next_pc_addr; + pb_linear_combination_array one_as_addr; + std::shared_ptr > pack_next_pc_addr; + + pb_variable packed_load_addr; + pb_variable packed_store_addr; + pb_variable packed_store_val; + + std::shared_ptr > increment_pc; + std::shared_ptr > compute_packed_load_addr; + std::shared_ptr > compute_packed_store_addr; + std::shared_ptr > compute_packed_store_val; + + pb_variable packed_ls_addr; + pb_variable packed_ls_prev_val; + pb_variable packed_ls_next_val; + pb_variable packed_prev_state; + pb_variable packed_next_state; + std::shared_ptr > pack_ls_addr; + std::shared_ptr > pack_ls_prev_val; + std::shared_ptr > pack_ls_next_val; + std::shared_ptr > pack_prev_state; + std::shared_ptr > pack_next_state; + + fooram_cpu_checker(fooram_protoboard &pb, + pb_variable_array &prev_pc_addr, + pb_variable_array &prev_pc_val, + pb_variable_array &prev_state, + pb_variable_array &ls_addr, + pb_variable_array &ls_prev_val, + pb_variable_array &ls_next_val, + pb_variable_array &next_state, + pb_variable_array &next_pc_addr, + pb_variable &next_has_accepted, + const std::string &annotation_prefix); + + void generate_r1cs_constraints(); + + void generate_r1cs_witness() { assert(0); } + + void generate_r1cs_witness_address(); + + void generate_r1cs_witness_other(fooram_input_tape_iterator &aux_it, + const fooram_input_tape_iterator &aux_end); + + void dump() const; +}; + +} // libsnark + +#include "gadgetlib1/gadgets/cpu_checkers/fooram/fooram_cpu_checker.tcc" + +#endif // FORAM_CPU_CHECKER_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/cpu_checkers/fooram/fooram_cpu_checker.tcc b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/cpu_checkers/fooram/fooram_cpu_checker.tcc new file mode 100644 index 0000000..0024714 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/cpu_checkers/fooram/fooram_cpu_checker.tcc @@ -0,0 +1,232 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for the FOORAM CPU checker gadget. + + See fooram_cpu_checker.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef FOORAM_CPU_CHECKER_TCC_ +#define FOORAM_CPU_CHECKER_TCC_ + +namespace libsnark { + +template +fooram_cpu_checker::fooram_cpu_checker(fooram_protoboard &pb, + pb_variable_array &prev_pc_addr, + pb_variable_array &prev_pc_val, + pb_variable_array &prev_state, + pb_variable_array &ls_addr, + pb_variable_array &ls_prev_val, + pb_variable_array &ls_next_val, + pb_variable_array &next_state, + pb_variable_array &next_pc_addr, + pb_variable &next_has_accepted, + const std::string &annotation_prefix) : + fooram_gadget(pb, annotation_prefix), + prev_pc_addr(prev_pc_addr), + prev_pc_val(prev_pc_val), + prev_state(prev_state), + ls_addr(ls_addr), + ls_prev_val(ls_prev_val), + ls_next_val(ls_next_val), + next_state(next_state), + next_pc_addr(next_pc_addr), + next_has_accepted(next_has_accepted) +{ + /* increment PC */ + packed_next_pc_addr.allocate(pb, FMT(annotation_prefix, " packed_next_pc_addr")); + pack_next_pc_addr.reset(new packing_gadget(pb, next_pc_addr, packed_next_pc_addr, FMT(annotation_prefix, " pack_next_pc_addr"))); + + one_as_addr.resize(next_pc_addr.size()); + one_as_addr[0].assign(this->pb, 1); + for (size_t i = 1; i < next_pc_addr.size(); ++i) + { + one_as_addr[i].assign(this->pb, 0); + } + + /* packed_next_pc_addr = prev_pc_addr + one_as_addr */ + increment_pc.reset(new bar_gadget(pb, prev_pc_addr, FieldT::one(), one_as_addr, FieldT::one(), packed_next_pc_addr, FMT(annotation_prefix, " increment_pc"))); + + /* packed_store_addr = prev_pc_addr + prev_pc_val */ + packed_store_addr.allocate(pb, FMT(annotation_prefix, " packed_store_addr")); + compute_packed_store_addr.reset(new bar_gadget(pb, prev_pc_addr, FieldT::one(), prev_pc_val, FieldT::one(), packed_store_addr, FMT(annotation_prefix, " compute_packed_store_addr"))); + + /* packed_load_addr = 2 * x + next_pc_addr */ + packed_load_addr.allocate(pb, FMT(annotation_prefix, " packed_load_addr")); + compute_packed_load_addr.reset(new bar_gadget(pb, prev_pc_val, FieldT(2), next_pc_addr, FieldT::one(), packed_load_addr, FMT(annotation_prefix, " compute_packed_load_addr"))); + + /* + packed_ls_addr = x0 * packed_load_addr + (1-x0) * packed_store_addr + packed_ls_addr ~ ls_addr + */ + packed_ls_addr.allocate(pb, FMT(annotation_prefix, " packed_ls_addr")); + pack_ls_addr.reset(new packing_gadget(pb, ls_addr, packed_ls_addr, " pack_ls_addr")); + + /* packed_store_val = prev_state_bits + prev_pc_addr */ + packed_store_val.allocate(pb, FMT(annotation_prefix, " packed_store_val")); + compute_packed_store_val.reset(new bar_gadget(pb, prev_state, FieldT::one(), prev_pc_addr, FieldT::one(), packed_store_val, FMT(annotation_prefix, " compute_packed_store_val"))); + + /* + packed_ls_next_val = x0 * packed_ls_prev_val + (1-x0) * packed_store_val + packed_ls_next_val ~ ls_next_val + */ + packed_ls_prev_val.allocate(pb, FMT(annotation_prefix, " packed_ls_prev_val")); + pack_ls_prev_val.reset(new packing_gadget(this->pb, ls_prev_val, packed_ls_prev_val, FMT(annotation_prefix, " pack_ls_prev_val"))); + packed_ls_next_val.allocate(pb, FMT(annotation_prefix, " packed_ls_next_val")); + pack_ls_next_val.reset(new packing_gadget(this->pb, ls_next_val, packed_ls_next_val, FMT(annotation_prefix, " pack_ls_next_val"))); + + /* + packed_next_state = x0 * packed_ls_prev_val + (1-x0) * packed_prev_state + packed_next_state ~ next_state + packed_prev_state ~ prev_state + */ + packed_prev_state.allocate(pb, FMT(annotation_prefix, " packed_prev_state")); + pack_prev_state.reset(new packing_gadget(pb, prev_state, packed_prev_state, " pack_prev_state")); + + packed_next_state.allocate(pb, FMT(annotation_prefix, " packed_next_state")); + pack_next_state.reset(new packing_gadget(pb, next_state, packed_next_state, " pack_next_state")); + + /* next_has_accepted = 1 */ +} + +template +void fooram_cpu_checker::generate_r1cs_constraints() +{ + /* packed_next_pc_addr = prev_pc_addr + one_as_addr */ + pack_next_pc_addr->generate_r1cs_constraints(false); + increment_pc->generate_r1cs_constraints(); + + /* packed_store_addr = prev_pc_addr + prev_pc_val */ + compute_packed_store_addr->generate_r1cs_constraints(); + + /* packed_load_addr = 2 * x + next_pc_addr */ + compute_packed_load_addr->generate_r1cs_constraints(); + + /* + packed_ls_addr = x0 * packed_load_addr + (1-x0) * packed_store_addr + packed_ls_addr - packed_store_addr = x0 * (packed_load_addr - packed_store_addr) + packed_ls_addr ~ ls_addr + */ + pack_ls_addr->generate_r1cs_constraints(false); + this->pb.add_r1cs_constraint(r1cs_constraint(prev_pc_val[0], + packed_load_addr - packed_store_addr, + packed_ls_addr - packed_store_addr), + FMT(this->annotation_prefix, " compute_ls_addr_packed")); + + /* packed_store_val = prev_state_bits + prev_pc_addr */ + compute_packed_store_val->generate_r1cs_constraints(); + + /* + packed_ls_next_val = x0 * packed_ls_prev_val + (1-x0) * packed_store_val + packed_ls_next_val - packed_store_val = x0 * (packed_ls_prev_val - packed_store_val) + packed_ls_next_val ~ ls_next_val + */ + pack_ls_prev_val->generate_r1cs_constraints(false); + pack_ls_next_val->generate_r1cs_constraints(false); + this->pb.add_r1cs_constraint(r1cs_constraint(prev_pc_val[0], + packed_ls_prev_val - packed_store_val, + packed_ls_next_val - packed_store_val), + FMT(this->annotation_prefix, " compute_packed_ls_next_val")); + + /* + packed_next_state = x0 * packed_ls_prev_val + (1-x0) * packed_prev_state + packed_next_state - packed_prev_state = x0 * (packed_ls_prev_val - packed_prev_state) + packed_next_state ~ next_state + packed_prev_state ~ prev_state + */ + pack_prev_state->generate_r1cs_constraints(false); + pack_next_state->generate_r1cs_constraints(false); + this->pb.add_r1cs_constraint(r1cs_constraint(prev_pc_val[0], + packed_ls_prev_val - packed_prev_state, + packed_next_state - packed_prev_state), + FMT(this->annotation_prefix, " compute_packed_next_state")); + + /* next_has_accepted = 1 */ + this->pb.add_r1cs_constraint(r1cs_constraint(1, next_has_accepted, 1), FMT(this->annotation_prefix, " always_accepted")); +} + +template +void fooram_cpu_checker::generate_r1cs_witness_address() +{ + one_as_addr.evaluate(this->pb); + + /* packed_next_pc_addr = prev_pc_addr + one_as_addr */ + increment_pc->generate_r1cs_witness(); + pack_next_pc_addr->generate_r1cs_witness_from_packed(); + + /* packed_store_addr = prev_pc_addr + prev_pc_val */ + compute_packed_store_addr->generate_r1cs_witness(); + + /* packed_load_addr = 2 * x + next_pc_addr */ + compute_packed_load_addr->generate_r1cs_witness(); + + /* + packed_ls_addr = x0 * packed_load_addr + (1-x0) * packed_store_addr + packed_ls_addr - packed_store_addr = x0 * (packed_load_addr - packed_store_addr) + packed_ls_addr ~ ls_addr + */ + this->pb.val(packed_ls_addr) = (this->pb.val(prev_pc_val[0]) * this->pb.val(packed_load_addr) + + (FieldT::one()-this->pb.val(prev_pc_val[0])) * this->pb.val(packed_store_addr)); + pack_ls_addr->generate_r1cs_witness_from_packed(); +} + +template +void fooram_cpu_checker::generate_r1cs_witness_other(fooram_input_tape_iterator &aux_it, + const fooram_input_tape_iterator &aux_end) +{ + /* fooram memory contents do not depend on program/input. */ + UNUSED(aux_it, aux_end); + /* packed_store_val = prev_state_bits + prev_pc_addr */ + compute_packed_store_val->generate_r1cs_witness(); + + /* + packed_ls_next_val = x0 * packed_ls_prev_val + (1-x0) * packed_store_val + packed_ls_next_val - packed_store_val = x0 * (packed_ls_prev_val - packed_store_val) + packed_ls_next_val ~ ls_next_val + */ + pack_ls_prev_val->generate_r1cs_witness_from_bits(); + this->pb.val(packed_ls_next_val) = (this->pb.val(prev_pc_val[0]) * this->pb.val(packed_ls_prev_val) + + (FieldT::one() - this->pb.val(prev_pc_val[0])) * this->pb.val(packed_store_val)); + pack_ls_next_val->generate_r1cs_witness_from_packed(); + + /* + packed_next_state = x0 * packed_ls_prev_val + (1-x0) * packed_prev_state + packed_next_state - packed_prev_state = x0 * (packed_ls_prev_val - packed_prev_state) + packed_next_state ~ next_state + packed_prev_state ~ prev_state + */ + pack_prev_state->generate_r1cs_witness_from_bits(); + this->pb.val(packed_next_state) = (this->pb.val(prev_pc_val[0]) * this->pb.val(packed_ls_prev_val) + + (FieldT::one() - this->pb.val(prev_pc_val[0])) * this->pb.val(packed_prev_state)); + pack_next_state->generate_r1cs_witness_from_packed(); + + /* next_has_accepted = 1 */ + this->pb.val(next_has_accepted) = FieldT::one(); +} + +template +void fooram_cpu_checker::dump() const +{ + printf("packed_store_addr: "); + this->pb.val(packed_store_addr).print(); + printf("packed_load_addr: "); + this->pb.val(packed_load_addr).print(); + printf("packed_ls_addr: "); + this->pb.val(packed_ls_addr).print(); + printf("packed_store_val: "); + this->pb.val(packed_store_val).print(); + printf("packed_ls_next_val: "); + this->pb.val(packed_ls_next_val).print(); + printf("packed_next_state: "); + this->pb.val(packed_next_state).print(); +} + +} // libsnark + +#endif // FOORAM_CPU_CHECKER_TCC diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/cpu_checkers/tinyram/components/alu_arithmetic.hpp b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/cpu_checkers/tinyram/components/alu_arithmetic.hpp new file mode 100644 index 0000000..f687a5a --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/cpu_checkers/tinyram/components/alu_arithmetic.hpp @@ -0,0 +1,684 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for the TinyRAM ALU arithmetic gadgets. + + These gadget check the correct execution of arithmetic TinyRAM instructions. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef ALU_ARITHMETIC_HPP_ +#define ALU_ARITHMETIC_HPP_ +#include + +#include "gadgetlib1/gadgets/cpu_checkers/tinyram/components/tinyram_protoboard.hpp" +#include "gadgetlib1/gadgets/basic_gadgets.hpp" + +namespace libsnark { + +/* arithmetic gadgets */ +template +class ALU_arithmetic_gadget : public tinyram_standard_gadget { +public: + const pb_variable_array opcode_indicators; + const word_variable_gadget desval; + const word_variable_gadget arg1val; + const word_variable_gadget arg2val; + const pb_variable flag; + const pb_variable result; + const pb_variable result_flag; + + ALU_arithmetic_gadget(tinyram_protoboard &pb, + const pb_variable_array &opcode_indicators, + const word_variable_gadget &desval, + const word_variable_gadget &arg1val, + const word_variable_gadget &arg2val, + const pb_variable &flag, + const pb_variable &result, + const pb_variable &result_flag, + const std::string &annotation_prefix="") : + tinyram_standard_gadget(pb, annotation_prefix), + opcode_indicators(opcode_indicators), + desval(desval), + arg1val(arg1val), + arg2val(arg2val), + flag(flag), + result(result), + result_flag(result_flag) {} +}; + +template +class ALU_and_gadget : public ALU_arithmetic_gadget { +private: + pb_variable_array res_word; + std::shared_ptr > pack_result; + std::shared_ptr > not_all_zeros; + pb_variable not_all_zeros_result; +public: + ALU_and_gadget(tinyram_protoboard &pb, + const pb_variable_array &opcode_indicators, + const word_variable_gadget &desval, + const word_variable_gadget &arg1val, + const word_variable_gadget &arg2val, + const pb_variable &flag, + const pb_variable &result, + const pb_variable &result_flag, + const std::string &annotation_prefix="") : + ALU_arithmetic_gadget(pb, opcode_indicators, desval, arg1val, arg2val, flag, result, result_flag, annotation_prefix) + { + res_word.allocate(pb, pb.ap.w, FMT(this->annotation_prefix, " res_bit")); + not_all_zeros_result.allocate(pb, FMT(this->annotation_prefix, " not_all_zeros_result")); + + pack_result.reset( + new packing_gadget(pb, res_word, result, + FMT(this->annotation_prefix, " pack_result"))); + not_all_zeros.reset( + new disjunction_gadget(pb, res_word, not_all_zeros_result, + FMT(this->annotation_prefix, "not_all_zeros"))); + } + + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +template +void test_ALU_and_gadget(const size_t w); + +template +class ALU_or_gadget : public ALU_arithmetic_gadget { +private: + pb_variable_array res_word; + std::shared_ptr > pack_result; + std::shared_ptr > not_all_zeros; + pb_variable not_all_zeros_result; +public: + ALU_or_gadget(tinyram_protoboard &pb, + const pb_variable_array &opcode_indicators, + const word_variable_gadget &desval, + const word_variable_gadget &arg1val, + const word_variable_gadget &arg2val, + const pb_variable &flag, + const pb_variable &result, + const pb_variable &result_flag, + const std::string &annotation_prefix="") : + ALU_arithmetic_gadget(pb, opcode_indicators, desval, arg1val, arg2val, flag, result, result_flag, annotation_prefix) + { + res_word.allocate(pb, pb.ap.w, FMT(this->annotation_prefix, " res_bit")); + not_all_zeros_result.allocate(pb, FMT(this->annotation_prefix, " not_all_zeros_result")); + + pack_result.reset( + new packing_gadget(pb, res_word, result, + FMT(this->annotation_prefix, " pack_result"))); + not_all_zeros.reset( + new disjunction_gadget(pb, res_word, not_all_zeros_result, + FMT(this->annotation_prefix, "not_all_zeros"))); + } + + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +template +void test_ALU_or_gadget(const size_t w); + +template +class ALU_xor_gadget : public ALU_arithmetic_gadget { +private: + pb_variable_array res_word; + std::shared_ptr > pack_result; + std::shared_ptr > not_all_zeros; + pb_variable not_all_zeros_result; +public: + ALU_xor_gadget(tinyram_protoboard &pb, + const pb_variable_array &opcode_indicators, + const word_variable_gadget &desval, + const word_variable_gadget &arg1val, + const word_variable_gadget &arg2val, + const pb_variable &flag, + const pb_variable &result, + const pb_variable &result_flag, + const std::string &annotation_prefix="") : + ALU_arithmetic_gadget(pb, opcode_indicators, desval, arg1val, arg2val, flag, result, result_flag, annotation_prefix) + { + res_word.allocate(pb, pb.ap.w, FMT(this->annotation_prefix, " res_bit")); + not_all_zeros_result.allocate(pb, FMT(this->annotation_prefix, " not_all_zeros_result")); + + pack_result.reset( + new packing_gadget(pb, res_word, result, + FMT(this->annotation_prefix, " pack_result"))); + not_all_zeros.reset( + new disjunction_gadget(pb, res_word, not_all_zeros_result, + FMT(this->annotation_prefix, "not_all_zeros"))); + } + + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +template +void test_ALU_xor_gadget(const size_t w); + +template +class ALU_not_gadget : public ALU_arithmetic_gadget { +/* we do bitwise not, because we need to compute flag */ +private: + pb_variable_array res_word; + std::shared_ptr > pack_result; + std::shared_ptr > not_all_zeros; + pb_variable not_all_zeros_result; +public: + ALU_not_gadget(tinyram_protoboard &pb, + const pb_variable_array &opcode_indicators, + const word_variable_gadget &desval, + const word_variable_gadget &arg1val, + const word_variable_gadget &arg2val, + const pb_variable &flag, + const pb_variable &result, + const pb_variable &result_flag, + const std::string &annotation_prefix="") : + ALU_arithmetic_gadget(pb, opcode_indicators, desval, arg1val, arg2val, flag, result, result_flag, annotation_prefix) + { + res_word.allocate(pb, pb.ap.w, FMT(this->annotation_prefix, " res_bit")); + not_all_zeros_result.allocate(pb, FMT(this->annotation_prefix, " not_all_zeros_result")); + + pack_result.reset( + new packing_gadget(pb, res_word, result, + FMT(this->annotation_prefix, " pack_result"))); + not_all_zeros.reset( + new disjunction_gadget(pb, res_word, not_all_zeros_result, + FMT(this->annotation_prefix, "not_all_zeros"))); + } + + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +template +void test_ALU_not_gadget(const size_t w); + +template +class ALU_add_gadget : public ALU_arithmetic_gadget { +private: + pb_variable addition_result; + pb_variable_array res_word; + pb_variable_array res_word_and_flag; + std::shared_ptr > unpack_addition, pack_result; +public: + ALU_add_gadget(tinyram_protoboard &pb, + const pb_variable_array &opcode_indicators, + const word_variable_gadget &desval, + const word_variable_gadget &arg1val, + const word_variable_gadget &arg2val, + const pb_variable &flag, + const pb_variable &result, + const pb_variable &result_flag, + const std::string &annotation_prefix="") : + ALU_arithmetic_gadget(pb, opcode_indicators, desval, arg1val, arg2val, flag, result, result_flag, annotation_prefix) + { + addition_result.allocate(pb, FMT(this->annotation_prefix, " addition_result")); + res_word.allocate(pb, pb.ap.w, FMT(this->annotation_prefix, " res_word")); + + res_word_and_flag = res_word; + res_word_and_flag.emplace_back(result_flag); + + unpack_addition.reset( + new packing_gadget(pb, res_word_and_flag, addition_result, + FMT(this->annotation_prefix, " unpack_addition"))); + pack_result.reset( + new packing_gadget(pb, res_word, result, + FMT(this->annotation_prefix, " pack_result"))); + } + + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +void test_ALU_add_gadget(const size_t w); + +template +class ALU_sub_gadget : public ALU_arithmetic_gadget { +private: + pb_variable intermediate_result; + pb_variable negated_flag; + pb_variable_array res_word; + pb_variable_array res_word_and_negated_flag; + + std::shared_ptr > unpack_intermediate, pack_result; +public: + ALU_sub_gadget(tinyram_protoboard &pb, + const pb_variable_array &opcode_indicators, + const word_variable_gadget &desval, + const word_variable_gadget &arg1val, + const word_variable_gadget &arg2val, + const pb_variable &flag, + const pb_variable &result, + const pb_variable &result_flag, + const std::string &annotation_prefix="") : + ALU_arithmetic_gadget(pb, opcode_indicators, desval, arg1val, arg2val, flag, result, result_flag, annotation_prefix) + { + intermediate_result.allocate(pb, FMT(this->annotation_prefix, " intermediate_result")); + negated_flag.allocate(pb, FMT(this->annotation_prefix, " negated_flag")); + res_word.allocate(pb, pb.ap.w, FMT(this->annotation_prefix, " res_word")); + + res_word_and_negated_flag = res_word; + res_word_and_negated_flag.emplace_back(negated_flag); + + unpack_intermediate.reset( + new packing_gadget(pb, res_word_and_negated_flag, intermediate_result, + FMT(this->annotation_prefix, " unpack_intermediate"))); + pack_result.reset( + new packing_gadget(pb, res_word, result, + FMT(this->annotation_prefix, " pack_result"))); + } + + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +void test_ALU_sub_gadget(const size_t w); + +template +class ALU_mov_gadget : public ALU_arithmetic_gadget { +public: + ALU_mov_gadget(tinyram_protoboard &pb, + const pb_variable_array &opcode_indicators, + const word_variable_gadget &desval, + const word_variable_gadget &arg1val, + const word_variable_gadget &arg2val, + const pb_variable &flag, + const pb_variable &result, + const pb_variable &result_flag, + const std::string &annotation_prefix="") : + ALU_arithmetic_gadget(pb, opcode_indicators, desval, arg1val, arg2val, flag, result, result_flag, annotation_prefix) {} + + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +template +void test_ALU_mov_gadget(const size_t w); + +template +class ALU_cmov_gadget : public ALU_arithmetic_gadget { +public: + ALU_cmov_gadget(tinyram_protoboard &pb, + const pb_variable_array &opcode_indicators, + const word_variable_gadget &desval, + const word_variable_gadget &arg1val, + const word_variable_gadget &arg2val, + const pb_variable &flag, + const pb_variable &result, + const pb_variable &result_flag, + const std::string &annotation_prefix="") : + ALU_arithmetic_gadget(pb, opcode_indicators, desval, arg1val, arg2val, flag, result, result_flag, annotation_prefix) + { + } + + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +template +void test_ALU_cmov_gadget(const size_t w); + +template +class ALU_cmp_gadget : public ALU_arithmetic_gadget { +private: + comparison_gadget comparator; +public: + const pb_variable cmpe_result; + const pb_variable cmpe_result_flag; + const pb_variable cmpa_result; + const pb_variable cmpa_result_flag; + const pb_variable cmpae_result; + const pb_variable cmpae_result_flag; + + ALU_cmp_gadget(tinyram_protoboard &pb, + const pb_variable_array &opcode_indicators, + const word_variable_gadget &desval, + const word_variable_gadget &arg1val, + const word_variable_gadget &arg2val, + const pb_variable &flag, + const pb_variable &cmpe_result, + const pb_variable &cmpe_result_flag, + const pb_variable &cmpa_result, + const pb_variable &cmpa_result_flag, + const pb_variable &cmpae_result, + const pb_variable &cmpae_result_flag, + const std::string &annotation_prefix="") : + ALU_arithmetic_gadget(pb, opcode_indicators, desval, arg1val, arg2val, flag, cmpa_result, cmpa_result_flag, annotation_prefix), + comparator(pb, pb.ap.w, arg2val.packed, arg1val.packed, cmpa_result_flag, cmpae_result_flag, + FMT(this->annotation_prefix, " comparator")), + cmpe_result(cmpe_result), cmpe_result_flag(cmpe_result_flag), + cmpa_result(cmpa_result), cmpa_result_flag(cmpa_result_flag), + cmpae_result(cmpae_result), cmpae_result_flag(cmpae_result_flag) {} + + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +template +void test_ALU_cmpe_gadget(const size_t w); + +template +void test_ALU_cmpa_gadget(const size_t w); + +template +void test_ALU_cmpae_gadget(const size_t w); + +template +class ALU_cmps_gadget : public ALU_arithmetic_gadget { +private: + pb_variable negated_arg1val_sign; + pb_variable negated_arg2val_sign; + pb_variable_array modified_arg1; + pb_variable_array modified_arg2; + pb_variable packed_modified_arg1; + pb_variable packed_modified_arg2; + std::shared_ptr > pack_modified_arg1; + std::shared_ptr > pack_modified_arg2; + std::shared_ptr > comparator; +public: + const pb_variable cmpg_result; + const pb_variable cmpg_result_flag; + const pb_variable cmpge_result; + const pb_variable cmpge_result_flag; + + ALU_cmps_gadget(tinyram_protoboard &pb, + const pb_variable_array &opcode_indicators, + const word_variable_gadget &desval, + const word_variable_gadget &arg1val, + const word_variable_gadget &arg2val, + const pb_variable &flag, + const pb_variable &cmpg_result, + const pb_variable &cmpg_result_flag, + const pb_variable &cmpge_result, + const pb_variable &cmpge_result_flag, + const std::string &annotation_prefix="") : + ALU_arithmetic_gadget(pb, opcode_indicators, desval, arg1val, arg2val, flag, cmpg_result, cmpg_result_flag, annotation_prefix), + cmpg_result(cmpg_result), cmpg_result_flag(cmpg_result_flag), + cmpge_result(cmpge_result), cmpge_result_flag(cmpge_result_flag) + { + negated_arg1val_sign.allocate(pb, FMT(this->annotation_prefix, " negated_arg1val_sign")); + negated_arg2val_sign.allocate(pb, FMT(this->annotation_prefix, " negated_arg2val_sign")); + + modified_arg1 = pb_variable_array(arg1val.bits.begin(), --arg1val.bits.end()); + modified_arg1.emplace_back(negated_arg1val_sign); + + modified_arg2 = pb_variable_array(arg2val.bits.begin(), --arg2val.bits.end()); + modified_arg2.emplace_back(negated_arg2val_sign); + + packed_modified_arg1.allocate(pb, FMT(this->annotation_prefix, " packed_modified_arg1")); + packed_modified_arg2.allocate(pb, FMT(this->annotation_prefix, " packed_modified_arg2")); + + pack_modified_arg1.reset(new packing_gadget(pb, modified_arg1, packed_modified_arg1, + FMT(this->annotation_prefix, " pack_modified_arg1"))); + pack_modified_arg2.reset(new packing_gadget(pb, modified_arg2, packed_modified_arg2, + FMT(this->annotation_prefix, " pack_modified_arg2"))); + + comparator.reset(new comparison_gadget(pb, pb.ap.w, + packed_modified_arg2, packed_modified_arg1, + cmpg_result_flag, cmpge_result_flag, + FMT(this->annotation_prefix, " comparator"))); + } + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +template +void test_ALU_cmpg_gadget(const size_t w); + +template +void test_ALU_cmpge_gadget(const size_t w); + +template +class ALU_umul_gadget : public ALU_arithmetic_gadget { +private: + dual_variable_gadget mul_result; + pb_variable_array mull_bits; + pb_variable_array umulh_bits; + pb_variable result_flag; + std::shared_ptr > pack_mull_result; + std::shared_ptr > pack_umulh_result; + std::shared_ptr > compute_flag; +public: + const pb_variable mull_result; + const pb_variable mull_flag; + const pb_variable umulh_result; + const pb_variable umulh_flag; + + ALU_umul_gadget(tinyram_protoboard &pb, + const pb_variable_array &opcode_indicators, + const word_variable_gadget &desval, + const word_variable_gadget &arg1val, + const word_variable_gadget &arg2val, + const pb_variable &flag, + const pb_variable &mull_result, + const pb_variable &mull_flag, + const pb_variable &umulh_result, + const pb_variable &umulh_flag, + const std::string &annotation_prefix="") : + ALU_arithmetic_gadget(pb, opcode_indicators, desval, arg1val, arg2val, flag, mull_result, mull_flag, annotation_prefix), + mul_result(pb, 2*pb.ap.w, FMT(this->annotation_prefix, " mul_result")), + mull_result(mull_result), mull_flag(mull_flag), umulh_result(umulh_result), umulh_flag(umulh_flag) + { + mull_bits.insert(mull_bits.end(), mul_result.bits.begin(), mul_result.bits.begin()+pb.ap.w); + umulh_bits.insert(umulh_bits.end(), mul_result.bits.begin()+pb.ap.w, mul_result.bits.begin()+2*pb.ap.w); + + pack_mull_result.reset(new packing_gadget(pb, mull_bits, mull_result, FMT(this->annotation_prefix, " pack_mull_result"))); + pack_umulh_result.reset(new packing_gadget(pb, umulh_bits, umulh_result, FMT(this->annotation_prefix, " pack_umulh_result"))); + + result_flag.allocate(pb, FMT(this->annotation_prefix, " result_flag")); + compute_flag.reset(new disjunction_gadget(pb, umulh_bits, result_flag, FMT(this->annotation_prefix, " compute_flag"))); + } + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +template +void test_ALU_mull_gadget(const size_t w); + +template +void test_ALU_umulh_gadget(const size_t w); + +template +class ALU_smul_gadget : public ALU_arithmetic_gadget { +private: + dual_variable_gadget mul_result; + pb_variable_array smulh_bits; + + pb_variable top; + std::shared_ptr > pack_top; + + pb_variable is_top_empty, is_top_empty_aux; + pb_variable is_top_full, is_top_full_aux; + + pb_variable result_flag; + std::shared_ptr > pack_smulh_result; +public: + const pb_variable smulh_result; + const pb_variable smulh_flag; + + ALU_smul_gadget(tinyram_protoboard &pb, + const pb_variable_array &opcode_indicators, + const word_variable_gadget &desval, + const word_variable_gadget &arg1val, + const word_variable_gadget &arg2val, + const pb_variable &flag, + const pb_variable &smulh_result, + const pb_variable &smulh_flag, + const std::string &annotation_prefix="") : + ALU_arithmetic_gadget(pb, opcode_indicators, desval, arg1val, arg2val, flag, smulh_result, smulh_flag, annotation_prefix), + mul_result(pb, 2*pb.ap.w+1, FMT(this->annotation_prefix, " mul_result")), /* see witness map for explanation for 2w+1 */ + smulh_result(smulh_result), smulh_flag(smulh_flag) + { + smulh_bits.insert(smulh_bits.end(), mul_result.bits.begin()+pb.ap.w, mul_result.bits.begin()+2*pb.ap.w); + + pack_smulh_result.reset(new packing_gadget(pb, smulh_bits, smulh_result, FMT(this->annotation_prefix, " pack_smulh_result"))); + + top.allocate(pb, FMT(this->annotation_prefix, " top")); + pack_top.reset(new packing_gadget(pb, pb_variable_array(mul_result.bits.begin() + pb.ap.w-1, mul_result.bits.begin() + 2*pb.ap.w), top, + FMT(this->annotation_prefix, " pack_top"))); + + is_top_empty.allocate(pb, FMT(this->annotation_prefix, " is_top_empty")); + is_top_empty_aux.allocate(pb, FMT(this->annotation_prefix, " is_top_empty_aux")); + + is_top_full.allocate(pb, FMT(this->annotation_prefix, " is_top_full")); + is_top_full_aux.allocate(pb, FMT(this->annotation_prefix, " is_top_full_aux")); + + result_flag.allocate(pb, FMT(this->annotation_prefix, " result_flag")); + } + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +template +void test_ALU_smulh_gadget(const size_t w); + +template +class ALU_divmod_gadget : public ALU_arithmetic_gadget { +/* + <<<<<<< Updated upstream + B * q + r = A_aux = A * B_nonzero + q * (1-B_nonzero) = 0 + A(r < B, less=B_nonzero, leq=ONE) + ======= + B * q + r = A + + r <= B + >>>>>>> Stashed changes +*/ +private: + pb_variable B_inv; + pb_variable B_nonzero; + pb_variable A_aux; + std::shared_ptr > r_less_B; +public: + const pb_variable udiv_result; + const pb_variable udiv_flag; + const pb_variable umod_result; + const pb_variable umod_flag; + + ALU_divmod_gadget(tinyram_protoboard &pb, + const pb_variable_array &opcode_indicators, + const word_variable_gadget &desval, + const word_variable_gadget &arg1val, + const word_variable_gadget &arg2val, + const pb_variable &flag, + const pb_variable &udiv_result, + const pb_variable &udiv_flag, + const pb_variable &umod_result, + const pb_variable &umod_flag, + const std::string &annotation_prefix="") : + ALU_arithmetic_gadget(pb, opcode_indicators, desval, arg1val, arg2val, flag, udiv_result, udiv_flag, annotation_prefix), + udiv_result(udiv_result), udiv_flag(udiv_flag), umod_result(umod_result), umod_flag(umod_flag) + { + B_inv.allocate(pb, FMT(this->annotation_prefix, " B_inv")); + B_nonzero.allocate(pb, FMT(this->annotation_prefix, " B_nonzer")); + A_aux.allocate(pb, FMT(this->annotation_prefix, " A_aux")); + r_less_B.reset(new comparison_gadget(pb, pb.ap.w, umod_result, arg2val.packed, + B_nonzero, ONE, FMT(this->annotation_prefix, " r_less_B"))); + } + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +template +void test_ALU_udiv_gadget(const size_t w); + +template +void test_ALU_umod_gadget(const size_t w); + +template +class ALU_shr_shl_gadget : public ALU_arithmetic_gadget { +private: + pb_variable reversed_input; + std::shared_ptr > pack_reversed_input; + + pb_variable_array barrel_right_internal; + std::vector > shifted_out_bits; + + pb_variable is_oversize_shift; + std::shared_ptr > check_oversize_shift; + pb_variable result; + + pb_variable_array result_bits; + std::shared_ptr > unpack_result; + pb_variable reversed_result; + std::shared_ptr > pack_reversed_result; +public: + pb_variable shr_result; + pb_variable shr_flag; + pb_variable shl_result; + pb_variable shl_flag; + + size_t logw; + + ALU_shr_shl_gadget(tinyram_protoboard &pb, + const pb_variable_array &opcode_indicators, + const word_variable_gadget &desval, + const word_variable_gadget &arg1val, + const word_variable_gadget &arg2val, + const pb_variable &flag, + const pb_variable &shr_result, + const pb_variable &shr_flag, + const pb_variable &shl_result, + const pb_variable &shl_flag, + const std::string &annotation_prefix="") : + ALU_arithmetic_gadget(pb, opcode_indicators, desval, arg1val, arg2val, flag, shr_result, shr_flag, annotation_prefix), + shr_result(shr_result), shr_flag(shr_flag), shl_result(shl_result), shl_flag(shl_flag) + { + logw = log2(pb.ap.w); + + reversed_input.allocate(pb, FMT(this->annotation_prefix, " reversed_input")); + pack_reversed_input.reset( + new packing_gadget(pb, pb_variable_array(arg1val.bits.rbegin(), arg1val.bits.rend()), + reversed_input, + FMT(this->annotation_prefix, " pack_reversed_input"))); + + barrel_right_internal.allocate(pb, logw+1, FMT(this->annotation_prefix, " barrel_right_internal")); + + shifted_out_bits.resize(logw); + for (size_t i = 0; i < logw; ++i) + { + shifted_out_bits[i].allocate(pb, 1ul<annotation_prefix, " shifted_out_bits_%zu", i)); + } + + is_oversize_shift.allocate(pb, FMT(this->annotation_prefix, " is_oversize_shift")); + check_oversize_shift.reset( + new disjunction_gadget(pb, + pb_variable_array(arg2val.bits.begin()+logw, arg2val.bits.end()), + is_oversize_shift, + FMT(this->annotation_prefix, " check_oversize_shift"))); + result.allocate(pb, FMT(this->annotation_prefix, " result")); + + result_bits.allocate(pb, pb.ap.w, FMT(this->annotation_prefix, " result_bits")); + unpack_result.reset( + new packing_gadget(pb, result_bits, result, //barrel_right_internal[logw], + FMT(this->annotation_prefix, " unpack_result"))); + + reversed_result.allocate(pb, FMT(this->annotation_prefix, " reversed_result")); + pack_reversed_result.reset( + new packing_gadget(pb, pb_variable_array(result_bits.rbegin(), result_bits.rend()), + reversed_result, + FMT(this->annotation_prefix, " pack_reversed_result"))); + } + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +template +void test_ALU_shr_gadget(const size_t w); + +template +void test_ALU_shl_gadget(const size_t w); + +} // libsnark + +#include "gadgetlib1/gadgets/cpu_checkers/tinyram/components/alu_arithmetic.tcc" + +#endif // ALU_ARITHMETIC_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/cpu_checkers/tinyram/components/alu_arithmetic.tcc b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/cpu_checkers/tinyram/components/alu_arithmetic.tcc new file mode 100644 index 0000000..170af28 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/cpu_checkers/tinyram/components/alu_arithmetic.tcc @@ -0,0 +1,1500 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for the TinyRAM ALU arithmetic gadgets. + + See alu_arithmetic.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef ALU_ARITHMETIC_TCC_ +#define ALU_ARITHMETIC_TCC_ + +#include "common/profiling.hpp" +#include "common/utils.hpp" + +namespace libsnark { + +/* the code here is full of template lambda magic, but it is better to + have limited presence of such code than to have code duplication in + testing functions, which basically do the same thing: brute force + the range of inputs which different success predicates */ + +template +using initializer_fn = + std::function&, // pb + pb_variable_array&, // opcode_indicators + word_variable_gadget&, // desval + word_variable_gadget&, // arg1val + word_variable_gadget&, // arg2val + pb_variable&, // flag + pb_variable&, // result + pb_variable& // result_flag + )>; + +template +void brute_force_arithmetic_gadget(const size_t w, + const size_t opcode, + initializer_fn initializer, + std::function res_function, + std::function flag_function) +/* parameters for res_function and flag_function are both desval, flag, arg1val, arg2val */ +{ + printf("testing on all %zu bit inputs\n", w); + + tinyram_architecture_params ap(w, 16); + tinyram_program P; P.instructions = generate_tinyram_prelude(ap); + tinyram_protoboard pb(ap, P.size(), 0, 10); + + pb_variable_array opcode_indicators; + opcode_indicators.allocate(pb, 1ul< desval(pb, "desval"); + desval.generate_r1cs_constraints(true); + word_variable_gadget arg1val(pb, "arg1val"); + arg1val.generate_r1cs_constraints(true); + word_variable_gadget arg2val(pb, "arg2val"); + arg2val.generate_r1cs_constraints(true); + pb_variable flag; flag.allocate(pb, "flag"); + pb_variable result; result.allocate(pb, "result"); + pb_variable result_flag; result_flag.allocate(pb, "result_flag"); + + std::unique_ptr g; + g.reset(initializer(pb, opcode_indicators, desval, arg1val, arg2val, flag, result, result_flag)); + g->generate_r1cs_constraints(); + + for (size_t des = 0; des < (1u << w); ++des) + { + pb.val(desval.packed) = FieldT(des); + desval.generate_r1cs_witness_from_packed(); + + for (char f = 0; f <= 1; ++f) + { + pb.val(flag) = (f ? FieldT::one() : FieldT::zero()); + + for (size_t arg1 = 0; arg1 < (1u << w); ++arg1) + { + pb.val(arg1val.packed) = FieldT(arg1); + arg1val.generate_r1cs_witness_from_packed(); + + for (size_t arg2 = 0; arg2 < (1u << w); ++arg2) + { + pb.val(arg2val.packed) = FieldT(arg2); + arg2val.generate_r1cs_witness_from_packed(); + + size_t res = res_function(des, f, arg1, arg2); + bool res_f = flag_function(des, f, arg1, arg2); +#ifdef DEBUG + printf("with the following parameters: flag = %d" + ", desval = %zu (%d)" + ", arg1val = %zu (%d)" + ", arg2val = %zu (%d)" + ". expected result: %zu (%d), expected flag: %d\n", + f, + des, from_twos_complement(des, w), + arg1, from_twos_complement(arg1, w), + arg2, from_twos_complement(arg2, w), + res, from_twos_complement(res, w), res_f); +#endif + g->generate_r1cs_witness(); +#ifdef DEBUG + printf("result: "); + pb.val(result).print(); + printf("flag: "); + pb.val(result_flag).print(); +#endif + assert(pb.is_satisfied()); + assert(pb.val(result) == FieldT(res)); + assert(pb.val(result_flag) == (res_f ? FieldT::one() : FieldT::zero())); + } + } + } + } +} + +/* and */ +template +void ALU_and_gadget::generate_r1cs_constraints() +{ + for (size_t i = 0; i < this->pb.ap.w; ++i) + { + this->pb.add_r1cs_constraint( + r1cs_constraint( + { this->arg1val.bits[i] }, + { this->arg2val.bits[i] }, + { this->res_word[i] }), + FMT(this->annotation_prefix, " res_word_%zu", i)); + } + + /* generate result */ + pack_result->generate_r1cs_constraints(false); + not_all_zeros->generate_r1cs_constraints(); + + /* result_flag = 1 - not_all_zeros = result is 0^w */ + this->pb.add_r1cs_constraint( + r1cs_constraint( + { ONE }, + { ONE, this->not_all_zeros_result * (-1) }, + { this->result_flag }), + FMT(this->annotation_prefix, " result_flag")); +} + +template +void ALU_and_gadget::generate_r1cs_witness() +{ + for (size_t i = 0; i < this->pb.ap.w; ++i) + { + bool b1 = this->pb.val(this->arg1val.bits[i]) == FieldT::one(); + bool b2 = this->pb.val(this->arg2val.bits[i]) == FieldT::one(); + + this->pb.val(this->res_word[i]) = (b1 && b2 ? FieldT::one() : FieldT::zero()); + } + + pack_result->generate_r1cs_witness_from_bits(); + not_all_zeros->generate_r1cs_witness(); + this->pb.val(this->result_flag) = FieldT::one() - this->pb.val(not_all_zeros_result); +} + +template +void test_ALU_and_gadget(const size_t w) +{ + print_time("starting and test"); + brute_force_arithmetic_gadget, FieldT>(w, + tinyram_opcode_AND, + [] (tinyram_protoboard &pb, + pb_variable_array &opcode_indicators, + word_variable_gadget &desval, + word_variable_gadget &arg1val, + word_variable_gadget &arg2val, + pb_variable &flag, + pb_variable &result, + pb_variable &result_flag) -> + ALU_and_gadget* { + return new ALU_and_gadget(pb, opcode_indicators, desval, arg1val, arg2val, flag, result, result_flag, "ALU_and_gadget"); + }, + [w] (size_t des, bool f, size_t x, size_t y) -> size_t { return x & y; }, + [w] (size_t des, bool f, size_t x, size_t y) -> bool { return (x & y) == 0; }); + print_time("and tests successful"); +} + +/* or */ +template +void ALU_or_gadget::generate_r1cs_constraints() +{ + for (size_t i = 0; i < this->pb.ap.w; ++i) + { + this->pb.add_r1cs_constraint( + r1cs_constraint( + { ONE, this->arg1val.bits[i] * (-1) }, + { ONE, this->arg2val.bits[i] * (-1) }, + { ONE, this->res_word[i] * (-1) }), + FMT(this->annotation_prefix, " res_word_%zu", i)); + } + + /* generate result */ + pack_result->generate_r1cs_constraints(false); + not_all_zeros->generate_r1cs_constraints(); + + /* result_flag = 1 - not_all_zeros = result is 0^w */ + this->pb.add_r1cs_constraint( + r1cs_constraint( + { ONE }, + { ONE, this->not_all_zeros_result * (-1) }, + { this->result_flag }), + FMT(this->annotation_prefix, " result_flag")); +} + +template +void ALU_or_gadget::generate_r1cs_witness() +{ + for (size_t i = 0; i < this->pb.ap.w; ++i) + { + bool b1 = this->pb.val(this->arg1val.bits[i]) == FieldT::one(); + bool b2 = this->pb.val(this->arg2val.bits[i]) == FieldT::one(); + + this->pb.val(this->res_word[i]) = (b1 || b2 ? FieldT::one() : FieldT::zero()); + } + + pack_result->generate_r1cs_witness_from_bits(); + not_all_zeros->generate_r1cs_witness(); + this->pb.val(this->result_flag) = FieldT::one() - this->pb.val(this->not_all_zeros_result); +} + +template +void test_ALU_or_gadget(const size_t w) +{ + print_time("starting or test"); + brute_force_arithmetic_gadget, FieldT>(w, + tinyram_opcode_OR, + [] (tinyram_protoboard &pb, + pb_variable_array &opcode_indicators, + word_variable_gadget &desval, + word_variable_gadget &arg1val, + word_variable_gadget &arg2val, + pb_variable &flag, + pb_variable &result, + pb_variable &result_flag) -> + ALU_or_gadget* { + return new ALU_or_gadget(pb, opcode_indicators, desval, arg1val, arg2val, flag, result, result_flag, "ALU_or_gadget"); + }, + [w] (size_t des, bool f, size_t x, size_t y) -> size_t { return x | y; }, + [w] (size_t des, bool f, size_t x, size_t y) -> bool { return (x | y) == 0; }); + print_time("or tests successful"); +} + +/* xor */ +template +void ALU_xor_gadget::generate_r1cs_constraints() +{ + for (size_t i = 0; i < this->pb.ap.w; ++i) + { + /* a = b ^ c <=> a = b + c - 2*b*c, (2*b)*c = b+c - a */ + this->pb.add_r1cs_constraint( + r1cs_constraint( + { this->arg1val.bits[i] * 2}, + { this->arg2val.bits[i] }, + { this->arg1val.bits[i], this->arg2val.bits[i], this->res_word[i] * (-1) }), + FMT(this->annotation_prefix, " res_word_%zu", i)); + } + + /* generate result */ + pack_result->generate_r1cs_constraints(false); + not_all_zeros->generate_r1cs_constraints(); + + /* result_flag = 1 - not_all_zeros = result is 0^w */ + this->pb.add_r1cs_constraint( + r1cs_constraint( + { ONE }, + { ONE, this->not_all_zeros_result * (-1) }, + { this->result_flag }), + FMT(this->annotation_prefix, " result_flag")); +} + +template +void ALU_xor_gadget::generate_r1cs_witness() +{ + for (size_t i = 0; i < this->pb.ap.w; ++i) + { + bool b1 = this->pb.val(this->arg1val.bits[i]) == FieldT::one(); + bool b2 = this->pb.val(this->arg2val.bits[i]) == FieldT::one(); + + this->pb.val(this->res_word[i]) = (b1 ^ b2 ? FieldT::one() : FieldT::zero()); + } + + pack_result->generate_r1cs_witness_from_bits(); + not_all_zeros->generate_r1cs_witness(); + this->pb.val(this->result_flag) = FieldT::one() - this->pb.val(this->not_all_zeros_result); +} + +template +void test_ALU_xor_gadget(const size_t w) +{ + print_time("starting xor test"); + brute_force_arithmetic_gadget, FieldT>(w, + tinyram_opcode_XOR, + [] (tinyram_protoboard &pb, + pb_variable_array &opcode_indicators, + word_variable_gadget &desval, + word_variable_gadget &arg1val, + word_variable_gadget &arg2val, + pb_variable &flag, + pb_variable &result, + pb_variable &result_flag) -> + ALU_xor_gadget* { + return new ALU_xor_gadget(pb, opcode_indicators, desval, arg1val, arg2val, flag, result, result_flag, "ALU_xor_gadget"); + }, + [w] (size_t des, bool f, size_t x, size_t y) -> size_t { return x ^ y; }, + [w] (size_t des, bool f, size_t x, size_t y) -> bool { return (x ^ y) == 0; }); + print_time("xor tests successful"); +} + +/* not */ +template +void ALU_not_gadget::generate_r1cs_constraints() +{ + for (size_t i = 0; i < this->pb.ap.w; ++i) + { + this->pb.add_r1cs_constraint( + r1cs_constraint( + { ONE }, + { ONE, this->arg2val.bits[i] * (-1) }, + { this->res_word[i] }), + FMT(this->annotation_prefix, " res_word_%zu", i)); + } + + /* generate result */ + pack_result->generate_r1cs_constraints(false); + not_all_zeros->generate_r1cs_constraints(); + + /* result_flag = 1 - not_all_zeros = result is 0^w */ + this->pb.add_r1cs_constraint( + r1cs_constraint( + { ONE }, + { ONE, this->not_all_zeros_result * (-1) }, + { this->result_flag }), + FMT(this->annotation_prefix, " result_flag")); +} + +template +void ALU_not_gadget::generate_r1cs_witness() +{ + for (size_t i = 0; i < this->pb.ap.w; ++i) + { + bool b2 = this->pb.val(this->arg2val.bits[i]) == FieldT::one(); + + this->pb.val(this->res_word[i]) = (!b2 ? FieldT::one() : FieldT::zero()); + } + + pack_result->generate_r1cs_witness_from_bits(); + not_all_zeros->generate_r1cs_witness(); + this->pb.val(this->result_flag) = FieldT::one() - this->pb.val(this->not_all_zeros_result); +} + +template +void test_ALU_not_gadget(const size_t w) +{ + print_time("starting not test"); + brute_force_arithmetic_gadget, FieldT>(w, + tinyram_opcode_NOT, + [] (tinyram_protoboard &pb, + pb_variable_array &opcode_indicators, + word_variable_gadget &desval, + word_variable_gadget &arg1val, + word_variable_gadget &arg2val, + pb_variable &flag, + pb_variable &result, + pb_variable &result_flag) -> + ALU_not_gadget* { + return new ALU_not_gadget(pb, opcode_indicators,desval, arg1val, arg2val, flag, result, result_flag, "ALU_not_gadget"); + }, + [w] (size_t des, bool f, size_t x, size_t y) -> size_t { return (1ul< bool { return ((1ul< +void ALU_add_gadget::generate_r1cs_constraints() +{ + /* addition_result = 1 * (arg1val + arg2val) */ + this->pb.add_r1cs_constraint( + r1cs_constraint( + { ONE }, + { this->arg1val.packed, this->arg2val.packed }, + { this->addition_result }), + FMT(this->annotation_prefix, " addition_result")); + + /* unpack into bits */ + unpack_addition->generate_r1cs_constraints(true); + + /* generate result */ + pack_result->generate_r1cs_constraints(false); +} + +template +void ALU_add_gadget::generate_r1cs_witness() +{ + this->pb.val(addition_result) = this->pb.val(this->arg1val.packed) + this->pb.val(this->arg2val.packed); + unpack_addition->generate_r1cs_witness_from_packed(); + pack_result->generate_r1cs_witness_from_bits(); +} + +template +void test_ALU_add_gadget(const size_t w) +{ + print_time("starting add test"); + brute_force_arithmetic_gadget, FieldT>(w, + tinyram_opcode_ADD, + [] (tinyram_protoboard &pb, + pb_variable_array &opcode_indicators, + word_variable_gadget &desval, + word_variable_gadget &arg1val, + word_variable_gadget &arg2val, + pb_variable &flag, + pb_variable &result, + pb_variable &result_flag) -> + ALU_add_gadget* { + return new ALU_add_gadget(pb, opcode_indicators, desval, arg1val, arg2val, flag, result, result_flag, "ALU_add_gadget"); + }, + [w] (size_t des, bool f, size_t x, size_t y) -> size_t { return (x+y) % (1ul< bool { return (x+y) >= (1ul< +void ALU_sub_gadget::generate_r1cs_constraints() +{ + /* intermediate_result = 2^w + (arg1val - arg2val) */ + FieldT twoi = FieldT::one(); + + linear_combination a, b, c; + + a.add_term(0, 1); + for (size_t i = 0; i < this->pb.ap.w; ++i) + { + twoi = twoi + twoi; + } + b.add_term(0, twoi); + b.add_term(this->arg1val.packed, 1); + b.add_term(this->arg2val.packed, -1); + c.add_term(intermediate_result, 1); + + this->pb.add_r1cs_constraint(r1cs_constraint(a, b, c), FMT(this->annotation_prefix, " main_constraint")); + + /* unpack into bits */ + unpack_intermediate->generate_r1cs_constraints(true); + + /* generate result */ + pack_result->generate_r1cs_constraints(false); + this->pb.add_r1cs_constraint( + r1cs_constraint( + { ONE }, + { ONE, this->negated_flag * (-1) }, + { this->result_flag }), + FMT(this->annotation_prefix, " result_flag")); +} + +template +void ALU_sub_gadget::generate_r1cs_witness() +{ + FieldT twoi = FieldT::one(); + for (size_t i = 0; i < this->pb.ap.w; ++i) + { + twoi = twoi + twoi; + } + + this->pb.val(intermediate_result) = twoi + this->pb.val(this->arg1val.packed) - this->pb.val(this->arg2val.packed); + unpack_intermediate->generate_r1cs_witness_from_packed(); + pack_result->generate_r1cs_witness_from_bits(); + this->pb.val(this->result_flag) = FieldT::one() - this->pb.val(this->negated_flag); +} + +template +void test_ALU_sub_gadget(const size_t w) +{ + print_time("starting sub test"); + brute_force_arithmetic_gadget, FieldT>(w, + tinyram_opcode_SUB, + [] (tinyram_protoboard &pb, + pb_variable_array &opcode_indicators, + word_variable_gadget &desval, + word_variable_gadget &arg1val, + word_variable_gadget &arg2val, + pb_variable &flag, + pb_variable &result, + pb_variable &result_flag) -> + ALU_sub_gadget* { + return new ALU_sub_gadget(pb, opcode_indicators, desval, arg1val, arg2val, flag, result, result_flag, "ALU_sub_gadget"); + }, + [w] (size_t des, bool f, size_t x, size_t y) -> size_t { + const size_t unsigned_result = ((1ul< bool { + const size_t msb = ((1ul<> w; + return (msb == 0); + }); + print_time("sub tests successful"); +} + +/* mov */ +template +void ALU_mov_gadget::generate_r1cs_constraints() +{ + this->pb.add_r1cs_constraint( + r1cs_constraint( + { ONE }, + { this->arg2val.packed }, + { this->result }), + FMT(this->annotation_prefix, " mov_result")); + + this->pb.add_r1cs_constraint( + r1cs_constraint( + { ONE }, + { this->flag }, + { this->result_flag }), + FMT(this->annotation_prefix, " mov_result_flag")); +} + +template +void ALU_mov_gadget::generate_r1cs_witness() +{ + this->pb.val(this->result) = this->pb.val(this->arg2val.packed); + this->pb.val(this->result_flag) = this->pb.val(this->flag); +} + +template +void test_ALU_mov_gadget(const size_t w) +{ + print_time("starting mov test"); + brute_force_arithmetic_gadget, FieldT>(w, + tinyram_opcode_MOV, + [] (tinyram_protoboard &pb, + pb_variable_array &opcode_indicators, + word_variable_gadget &desval, + word_variable_gadget &arg1val, + word_variable_gadget &arg2val, + pb_variable &flag, + pb_variable &result, + pb_variable &result_flag) -> + ALU_mov_gadget* { + return new ALU_mov_gadget(pb, opcode_indicators, desval, arg1val, arg2val, flag, result, result_flag, "ALU_mov_gadget"); + }, + [w] (size_t des, bool f, size_t x, size_t y) -> size_t { return y; }, + [w] (size_t des, bool f, size_t x, size_t y) -> bool { return f; }); + print_time("mov tests successful"); +} + +/* cmov */ +template +void ALU_cmov_gadget::generate_r1cs_constraints() +{ + /* + flag1 * arg2val + (1-flag1) * desval = result + flag1 * (arg2val - desval) = result - desval + */ + this->pb.add_r1cs_constraint( + r1cs_constraint( + { this->flag }, + { this->arg2val.packed, this->desval.packed * (-1) }, + { this->result, this->desval.packed * (-1) }), + FMT(this->annotation_prefix, " cmov_result")); + + this->pb.add_r1cs_constraint( + r1cs_constraint( + { ONE }, + { this->flag }, + { this->result_flag }), + FMT(this->annotation_prefix, " cmov_result_flag")); +} + +template +void ALU_cmov_gadget::generate_r1cs_witness() +{ + this->pb.val(this->result) = ((this->pb.val(this->flag) == FieldT::one()) ? + this->pb.val(this->arg2val.packed) : + this->pb.val(this->desval.packed)); + this->pb.val(this->result_flag) = this->pb.val(this->flag); +} + +template +void test_ALU_cmov_gadget(const size_t w) +{ + print_time("starting cmov test"); + brute_force_arithmetic_gadget, FieldT>(w, + tinyram_opcode_CMOV, + [] (tinyram_protoboard &pb, + pb_variable_array &opcode_indicators, + word_variable_gadget &desval, + word_variable_gadget &arg1val, + word_variable_gadget &arg2val, + pb_variable &flag, + pb_variable &result, + pb_variable &result_flag) -> + ALU_cmov_gadget* { + return new ALU_cmov_gadget(pb, opcode_indicators, desval, arg1val, arg2val, flag, result, result_flag, "ALU_cmov_gadget"); + }, + [w] (size_t des, bool f, size_t x, size_t y) -> size_t { return f ? y : des; }, + [w] (size_t des, bool f, size_t x, size_t y) -> bool { return f; }); + print_time("cmov tests successful"); +} + +/* unsigned comparison */ +template +void ALU_cmp_gadget::generate_r1cs_constraints() +{ + comparator.generate_r1cs_constraints(); + /* + cmpe = cmpae * (1-cmpa) + */ + this->pb.add_r1cs_constraint( + r1cs_constraint( + { cmpae_result_flag }, + { ONE, cmpa_result_flag * (-1) }, + { cmpe_result_flag }), + FMT(this->annotation_prefix, " cmpa_result_flag")); + + /* copy over results */ + this->pb.add_r1cs_constraint( + r1cs_constraint( + { ONE }, + { this->desval.packed }, + { cmpe_result }), + FMT(this->annotation_prefix, " cmpe_result")); + + this->pb.add_r1cs_constraint( + r1cs_constraint( + { ONE }, + { this->desval.packed }, + { cmpa_result }), + FMT(this->annotation_prefix, " cmpa_result")); + + this->pb.add_r1cs_constraint( + r1cs_constraint( + { ONE }, + { this->desval.packed }, + { cmpae_result }), + FMT(this->annotation_prefix, " cmpae_result")); +} + +template +void ALU_cmp_gadget::generate_r1cs_witness() +{ + comparator.generate_r1cs_witness(); + + this->pb.val(cmpe_result) = this->pb.val(this->desval.packed); + this->pb.val(cmpa_result) = this->pb.val(this->desval.packed); + this->pb.val(cmpae_result) = this->pb.val(this->desval.packed); + + this->pb.val(cmpe_result_flag) = ((this->pb.val(cmpae_result_flag) == FieldT::one()) && + (this->pb.val(cmpa_result_flag) == FieldT::zero()) ? + FieldT::one() : + FieldT::zero()); +} + +template +void test_ALU_cmpe_gadget(const size_t w) +{ + print_time("starting cmpe test"); + brute_force_arithmetic_gadget, FieldT>(w, + tinyram_opcode_CMPE, + [] (tinyram_protoboard &pb, + pb_variable_array &opcode_indicators, + word_variable_gadget &desval, + word_variable_gadget &arg1val, + word_variable_gadget &arg2val, + pb_variable &flag, + pb_variable &result, + pb_variable &result_flag) -> + ALU_cmp_gadget* { + pb_variable cmpa_result; cmpa_result.allocate(pb, "cmpa_result"); + pb_variable cmpa_result_flag; cmpa_result_flag.allocate(pb, "cmpa_result_flag"); + pb_variable cmpae_result; cmpae_result.allocate(pb, "cmpae_result"); + pb_variable cmpae_result_flag; cmpae_result_flag.allocate(pb, "cmpae_result_flag"); + return new ALU_cmp_gadget(pb, opcode_indicators, desval, arg1val, arg2val, flag, + result, result_flag, + cmpa_result, cmpa_result_flag, + cmpae_result, cmpae_result_flag, "ALU_cmp_gadget"); + }, + [w] (size_t des, bool f, size_t x, size_t y) -> size_t { return des; }, + [w] (size_t des, bool f, size_t x, size_t y) -> bool { return x == y; }); + print_time("cmpe tests successful"); +} + +template +void test_ALU_cmpa_gadget(const size_t w) +{ + print_time("starting cmpa test"); + brute_force_arithmetic_gadget, FieldT>(w, + tinyram_opcode_CMPA, + [] (tinyram_protoboard &pb, + pb_variable_array &opcode_indicators, + word_variable_gadget &desval, + word_variable_gadget &arg1val, + word_variable_gadget &arg2val, + pb_variable &flag, + pb_variable &result, + pb_variable &result_flag) -> + ALU_cmp_gadget* { + pb_variable cmpe_result; cmpe_result.allocate(pb, "cmpe_result"); + pb_variable cmpe_result_flag; cmpe_result_flag.allocate(pb, "cmpe_result_flag"); + pb_variable cmpae_result; cmpae_result.allocate(pb, "cmpae_result"); + pb_variable cmpae_result_flag; cmpae_result_flag.allocate(pb, "cmpae_result_flag"); + return new ALU_cmp_gadget(pb, opcode_indicators, desval, arg1val, arg2val, flag, + cmpe_result, cmpe_result_flag, + result, result_flag, + cmpae_result, cmpae_result_flag, "ALU_cmp_gadget"); + }, + [w] (size_t des, bool f, size_t x, size_t y) -> size_t { return des; }, + [w] (size_t des, bool f, size_t x, size_t y) -> bool { return x > y; }); + print_time("cmpa tests successful"); +} + +template +void test_ALU_cmpae_gadget(const size_t w) +{ + print_time("starting cmpae test"); + brute_force_arithmetic_gadget, FieldT>(w, + tinyram_opcode_CMPAE, + [] (tinyram_protoboard &pb, + pb_variable_array &opcode_indicators, + word_variable_gadget &desval, + word_variable_gadget &arg1val, + word_variable_gadget &arg2val, + pb_variable &flag, + pb_variable &result, + pb_variable &result_flag) -> + ALU_cmp_gadget* { + pb_variable cmpe_result; cmpe_result.allocate(pb, "cmpe_result"); + pb_variable cmpe_result_flag; cmpe_result_flag.allocate(pb, "cmpe_result_flag"); + pb_variable cmpa_result; cmpa_result.allocate(pb, "cmpa_result"); + pb_variable cmpa_result_flag; cmpa_result_flag.allocate(pb, "cmpa_result_flag"); + return new ALU_cmp_gadget(pb, opcode_indicators, desval, arg1val, arg2val, flag, + cmpe_result, cmpe_result_flag, + cmpa_result, cmpa_result_flag, + result, result_flag, "ALU_cmp_gadget"); + }, + [w] (size_t des, bool f, size_t x, size_t y) -> size_t { return des; }, + [w] (size_t des, bool f, size_t x, size_t y) -> bool { return x >= y; }); + print_time("cmpae tests successful"); +} + +/* signed comparison */ +template +void ALU_cmps_gadget::generate_r1cs_constraints() +{ + /* negate sign bits */ + this->pb.add_r1cs_constraint( + r1cs_constraint( + { ONE }, + { ONE, this->arg1val.bits[this->pb.ap.w-1] * (-1) }, + { negated_arg1val_sign }), + FMT(this->annotation_prefix, " negated_arg1val_sign")); + this->pb.add_r1cs_constraint( + r1cs_constraint( + { ONE }, + { ONE, this->arg2val.bits[this->pb.ap.w-1] * (-1) }, + { negated_arg2val_sign }), + FMT(this->annotation_prefix, " negated_arg2val_sign")); + + /* pack */ + pack_modified_arg1->generate_r1cs_constraints(false); + pack_modified_arg2->generate_r1cs_constraints(false); + + /* compare */ + comparator->generate_r1cs_constraints(); + + /* copy over results */ + this->pb.add_r1cs_constraint( + r1cs_constraint( + { ONE }, + { this->desval.packed }, + { cmpg_result }), + FMT(this->annotation_prefix, " cmpg_result")); + + this->pb.add_r1cs_constraint( + r1cs_constraint( + { ONE }, + { this->desval.packed }, + { cmpge_result }), + FMT(this->annotation_prefix, " cmpge_result")); +} + +template +void ALU_cmps_gadget::generate_r1cs_witness() +{ + /* negate sign bits */ + this->pb.val(negated_arg1val_sign) = FieldT::one() - this->pb.val(this->arg1val.bits[this->pb.ap.w-1]); + this->pb.val(negated_arg2val_sign) = FieldT::one() - this->pb.val(this->arg2val.bits[this->pb.ap.w-1]); + + /* pack */ + pack_modified_arg1->generate_r1cs_witness_from_bits(); + pack_modified_arg2->generate_r1cs_witness_from_bits(); + + /* produce result */ + comparator->generate_r1cs_witness(); + + this->pb.val(cmpg_result) = this->pb.val(this->desval.packed); + this->pb.val(cmpge_result) = this->pb.val(this->desval.packed); +} + +template +void test_ALU_cmpg_gadget(const size_t w) +{ + print_time("starting cmpg test"); + brute_force_arithmetic_gadget, FieldT>(w, + tinyram_opcode_CMPG, + [] (tinyram_protoboard &pb, + pb_variable_array &opcode_indicators, + word_variable_gadget &desval, + word_variable_gadget &arg1val, + word_variable_gadget &arg2val, + pb_variable &flag, + pb_variable &result, + pb_variable &result_flag) -> + ALU_cmps_gadget* { + pb_variable cmpge_result; cmpge_result.allocate(pb, "cmpge_result"); + pb_variable cmpge_result_flag; cmpge_result_flag.allocate(pb, "cmpge_result_flag"); + return new ALU_cmps_gadget(pb, opcode_indicators, desval, arg1val, arg2val, flag, + result, result_flag, + cmpge_result, cmpge_result_flag, "ALU_cmps_gadget"); + }, + [w] (size_t des, bool f, size_t x, size_t y) -> size_t { return des; }, + [w] (size_t des, bool f, size_t x, size_t y) -> bool { + return (from_twos_complement(x, w) > + from_twos_complement(y, w)); + }); + print_time("cmpg tests successful"); +} + +template +void test_ALU_cmpge_gadget(const size_t w) +{ + print_time("starting cmpge test"); + brute_force_arithmetic_gadget, FieldT>(w, + tinyram_opcode_CMPGE, + [] (tinyram_protoboard &pb, + pb_variable_array &opcode_indicators, + word_variable_gadget &desval, + word_variable_gadget &arg1val, + word_variable_gadget &arg2val, + pb_variable &flag, + pb_variable &result, + pb_variable &result_flag) -> + ALU_cmps_gadget* { + pb_variable cmpg_result; cmpg_result.allocate(pb, "cmpg_result"); + pb_variable cmpg_result_flag; cmpg_result_flag.allocate(pb, "cmpg_result_flag"); + return new ALU_cmps_gadget(pb, opcode_indicators, desval, arg1val, arg2val, flag, + cmpg_result, cmpg_result_flag, + result, result_flag, "ALU_cmps_gadget"); + }, + [w] (size_t des, bool f, size_t x, size_t y) -> size_t { return des; }, + [w] (size_t des, bool f, size_t x, size_t y) -> bool { + return (from_twos_complement(x, w) >= + from_twos_complement(y, w)); + }); + print_time("cmpge tests successful"); +} + +template +void ALU_umul_gadget::generate_r1cs_constraints() +{ + /* do multiplication */ + this->pb.add_r1cs_constraint( + r1cs_constraint( + { this->arg1val.packed }, + { this->arg2val.packed }, + { mul_result.packed }), + FMT(this->annotation_prefix, " main_constraint")); + mul_result.generate_r1cs_constraints(true); + + /* pack result */ + pack_mull_result->generate_r1cs_constraints(false); + pack_umulh_result->generate_r1cs_constraints(false); + + /* compute flag */ + compute_flag->generate_r1cs_constraints(); + + this->pb.add_r1cs_constraint( + r1cs_constraint( + { ONE }, + { this->result_flag }, + { mull_flag }), + FMT(this->annotation_prefix, " mull_flag")); + + this->pb.add_r1cs_constraint( + r1cs_constraint( + { ONE }, + { this->result_flag }, + { umulh_flag }), + FMT(this->annotation_prefix, " umulh_flag")); +} + +template +void ALU_umul_gadget::generate_r1cs_witness() +{ + /* do multiplication */ + this->pb.val(mul_result.packed) = this->pb.val(this->arg1val.packed) * this->pb.val(this->arg2val.packed); + mul_result.generate_r1cs_witness_from_packed(); + + /* pack result */ + pack_mull_result->generate_r1cs_witness_from_bits(); + pack_umulh_result->generate_r1cs_witness_from_bits(); + + /* compute flag */ + compute_flag->generate_r1cs_witness(); + + this->pb.val(mull_flag) = this->pb.val(this->result_flag); + this->pb.val(umulh_flag) = this->pb.val(this->result_flag); +} + +template +void test_ALU_mull_gadget(const size_t w) +{ + print_time("starting mull test"); + brute_force_arithmetic_gadget, FieldT>(w, + tinyram_opcode_MULL, + [] (tinyram_protoboard &pb, + pb_variable_array &opcode_indicators, + word_variable_gadget &desval, + word_variable_gadget &arg1val, + word_variable_gadget &arg2val, + pb_variable &flag, + pb_variable &result, + pb_variable &result_flag) -> + ALU_umul_gadget* { + pb_variable umulh_result; umulh_result.allocate(pb, "umulh_result"); + pb_variable umulh_flag; umulh_flag.allocate(pb, "umulh_flag"); + return new ALU_umul_gadget(pb, opcode_indicators, desval, arg1val, arg2val, flag, + result, result_flag, + umulh_result, umulh_flag, + "ALU_umul_gadget"); + }, + [w] (size_t des, bool f, size_t x, size_t y) -> size_t { return (x*y) % (1ul< bool { + return ((x*y) >> w) != 0; + }); + print_time("mull tests successful"); +} + +template +void test_ALU_umulh_gadget(const size_t w) +{ + print_time("starting umulh test"); + brute_force_arithmetic_gadget, FieldT>(w, + tinyram_opcode_UMULH, + [] (tinyram_protoboard &pb, + pb_variable_array &opcode_indicators, + word_variable_gadget &desval, + word_variable_gadget &arg1val, + word_variable_gadget &arg2val, + pb_variable &flag, + pb_variable &result, + pb_variable &result_flag) -> + ALU_umul_gadget* { + pb_variable mull_result; mull_result.allocate(pb, "mull_result"); + pb_variable mull_flag; mull_flag.allocate(pb, "mull_flag"); + return new ALU_umul_gadget(pb, opcode_indicators, desval, arg1val, arg2val, flag, + mull_result, mull_flag, + result, result_flag, + "ALU_umul_gadget"); + }, + [w] (size_t des, bool f, size_t x, size_t y) -> size_t { return (x*y) >> w; }, + [w] (size_t des, bool f, size_t x, size_t y) -> bool { + return ((x*y) >> w) != 0; + }); + print_time("umulh tests successful"); +} + +template +void ALU_smul_gadget::generate_r1cs_constraints() +{ + /* do multiplication */ + /* + from two's complement: (packed - 2^w * bits[w-1]) + to two's complement: lower order bits of 2^{2w} + result_of_* + */ + + linear_combination a, b, c; + a.add_term(this->arg1val.packed, 1); + a.add_term(this->arg1val.bits[this->pb.ap.w-1], -(FieldT(2)^this->pb.ap.w)); + b.add_term(this->arg2val.packed, 1); + b.add_term(this->arg2val.bits[this->pb.ap.w-1], -(FieldT(2)^this->pb.ap.w)); + c.add_term(mul_result.packed, 1); + c.add_term(ONE, -(FieldT(2)^(2*this->pb.ap.w))); + this->pb.add_r1cs_constraint(r1cs_constraint(a, b, c), FMT(this->annotation_prefix, " main_constraint")); + + mul_result.generate_r1cs_constraints(true); + + /* pack result */ + pack_smulh_result->generate_r1cs_constraints(false); + + /* compute flag */ + pack_top->generate_r1cs_constraints(false); + + /* + the gadgets below are FieldT specific: + I * X = (1-R) + R * X = 0 + + if X = 0 then R = 1 + if X != 0 then R = 0 and I = X^{-1} + */ + this->pb.add_r1cs_constraint( + r1cs_constraint( + { is_top_empty_aux }, + { top }, + { ONE, is_top_empty * (-1) }), + FMT(this->annotation_prefix, " I*X=1-R (is_top_empty)")); + this->pb.add_r1cs_constraint( + r1cs_constraint( + { is_top_empty }, + { top }, + { ONE * 0 }), + FMT(this->annotation_prefix, " R*X=0 (is_top_full)")); + + this->pb.add_r1cs_constraint( + r1cs_constraint( + { is_top_full_aux }, + { top, ONE * (1l-(1ul<<(this->pb.ap.w+1))) }, + { ONE, is_top_full * (-1) }), + FMT(this->annotation_prefix, " I*X=1-R (is_top_full)")); + this->pb.add_r1cs_constraint( + r1cs_constraint( + { is_top_full }, + { top, ONE * (1l-(1ul<<(this->pb.ap.w+1))) }, + { ONE * 0 }), + FMT(this->annotation_prefix, " R*X=0 (is_top_full)")); + + /* smulh_flag = 1 - (is_top_full + is_top_empty) */ + this->pb.add_r1cs_constraint( + r1cs_constraint( + { ONE }, + { ONE, is_top_full * (-1), is_top_empty * (-1) }, + { smulh_flag }), + FMT(this->annotation_prefix, " smulh_flag")); +} + +template +void ALU_smul_gadget::generate_r1cs_witness() +{ + /* do multiplication */ + /* + from two's complement: (packed - 2^w * bits[w-1]) + to two's complement: lower order bits of (2^{2w} + result_of_mul) + */ + this->pb.val(mul_result.packed) = + (this->pb.val(this->arg1val.packed) - (this->pb.val(this->arg1val.bits[this->pb.ap.w-1])*(FieldT(2)^this->pb.ap.w))) * + (this->pb.val(this->arg2val.packed) - (this->pb.val(this->arg2val.bits[this->pb.ap.w-1])*(FieldT(2)^this->pb.ap.w))) + + (FieldT(2)^(2*this->pb.ap.w)); + + mul_result.generate_r1cs_witness_from_packed(); + + /* pack result */ + pack_smulh_result->generate_r1cs_witness_from_bits(); + + /* compute flag */ + pack_top->generate_r1cs_witness_from_bits(); + size_t topval = this->pb.val(top).as_ulong(); + + if (topval == 0) + { + this->pb.val(is_top_empty) = FieldT::one(); + this->pb.val(is_top_empty_aux) = FieldT::zero(); + } + else + { + this->pb.val(is_top_empty) = FieldT::zero(); + this->pb.val(is_top_empty_aux) = this->pb.val(top).inverse(); + } + + if (topval == ((1ul<<(this->pb.ap.w+1))-1)) + { + this->pb.val(is_top_full) = FieldT::one(); + this->pb.val(is_top_full_aux) = FieldT::zero(); + } + else + { + this->pb.val(is_top_full) = FieldT::zero(); + this->pb.val(is_top_full_aux) = (this->pb.val(top)-FieldT((1ul<<(this->pb.ap.w+1))-1)).inverse(); + } + + /* smulh_flag = 1 - (is_top_full + is_top_empty) */ + this->pb.val(smulh_flag) = FieldT::one() - (this->pb.val(is_top_full) + this->pb.val(is_top_empty)); +} + +template +void test_ALU_smulh_gadget(const size_t w) +{ + print_time("starting smulh test"); + brute_force_arithmetic_gadget, FieldT>(w, + tinyram_opcode_SMULH, + [] (tinyram_protoboard &pb, + pb_variable_array &opcode_indicators, + word_variable_gadget &desval, + word_variable_gadget &arg1val, + word_variable_gadget &arg2val, + pb_variable &flag, + pb_variable &result, + pb_variable &result_flag) -> + ALU_smul_gadget* { + return new ALU_smul_gadget(pb, opcode_indicators, desval, arg1val, arg2val, flag, + result, result_flag, + "ALU_smul_gadget"); + }, + [w] (size_t des, bool f, size_t x, size_t y) -> size_t { + const size_t res = to_twos_complement((from_twos_complement(x, w) * from_twos_complement(y, w)), 2*w); + return res >> w; + }, + [w] (size_t des, bool f, size_t x, size_t y) -> bool { + const int res = from_twos_complement(x, w) * from_twos_complement(y, w); + const int truncated_res = from_twos_complement(to_twos_complement(res, 2*w) & ((1ul< +void ALU_divmod_gadget::generate_r1cs_constraints() +{ + /* B_inv * B = B_nonzero */ + linear_combination a1, b1, c1; + a1.add_term(B_inv, 1); + b1.add_term(this->arg2val.packed, 1); + c1.add_term(B_nonzero, 1); + + this->pb.add_r1cs_constraint(r1cs_constraint(a1, b1, c1), FMT(this->annotation_prefix, " B_inv*B=B_nonzero")); + + /* (1-B_nonzero) * B = 0 */ + linear_combination a2, b2, c2; + a2.add_term(ONE, 1); + a2.add_term(B_nonzero, -1); + b2.add_term(this->arg2val.packed, 1); + c2.add_term(ONE, 0); + + this->pb.add_r1cs_constraint(r1cs_constraint(a2, b2, c2), FMT(this->annotation_prefix, " (1-B_nonzero)*B=0")); + + /* B * q + r = A_aux = A * B_nonzero */ + linear_combination a3, b3, c3; + a3.add_term(this->arg2val.packed, 1); + b3.add_term(udiv_result, 1); + c3.add_term(A_aux, 1); + c3.add_term(umod_result, -1); + + this->pb.add_r1cs_constraint(r1cs_constraint(a3, b3, c3), FMT(this->annotation_prefix, " B*q+r=A_aux")); + + linear_combination a4, b4, c4; + a4.add_term(this->arg1val.packed, 1); + b4.add_term(B_nonzero, 1); + c4.add_term(A_aux, 1); + + this->pb.add_r1cs_constraint(r1cs_constraint(a4, b4, c4), FMT(this->annotation_prefix, " A_aux=A*B_nonzero")); + + /* q * (1-B_nonzero) = 0 */ + linear_combination a5, b5, c5; + a5.add_term(udiv_result, 1); + b5.add_term(ONE, 1); + b5.add_term(B_nonzero, -1); + c5.add_term(ONE, 0); + + this->pb.add_r1cs_constraint(r1cs_constraint(a5, b5, c5), FMT(this->annotation_prefix, " q*B_nonzero=0")); + + /* A(B, r, less=B_nonzero, leq=ONE) */ + r_less_B->generate_r1cs_constraints(); +} + +template +void ALU_divmod_gadget::generate_r1cs_witness() +{ + if (this->pb.val(this->arg2val.packed) == FieldT::zero()) + { + this->pb.val(B_inv) = FieldT::zero(); + this->pb.val(B_nonzero) = FieldT::zero(); + + this->pb.val(A_aux) = FieldT::zero(); + + this->pb.val(udiv_result) = FieldT::zero(); + this->pb.val(umod_result) = FieldT::zero(); + + this->pb.val(udiv_flag) = FieldT::one(); + this->pb.val(umod_flag) = FieldT::one(); + } + else + { + this->pb.val(B_inv) = this->pb.val(this->arg2val.packed).inverse(); + this->pb.val(B_nonzero) = FieldT::one(); + + const size_t A = this->pb.val(this->arg1val.packed).as_ulong(); + const size_t B = this->pb.val(this->arg2val.packed).as_ulong(); + + this->pb.val(A_aux) = this->pb.val(this->arg1val.packed); + + this->pb.val(udiv_result) = FieldT(A / B); + this->pb.val(umod_result) = FieldT(A % B); + + this->pb.val(udiv_flag) = FieldT::zero(); + this->pb.val(umod_flag) = FieldT::zero(); + } + + r_less_B->generate_r1cs_witness(); +} + +template +void test_ALU_udiv_gadget(const size_t w) +{ + print_time("starting udiv test"); + brute_force_arithmetic_gadget, FieldT>(w, + tinyram_opcode_UDIV, + [] (tinyram_protoboard &pb, + pb_variable_array &opcode_indicators, + word_variable_gadget &desval, + word_variable_gadget &arg1val, + word_variable_gadget &arg2val, + pb_variable &flag, + pb_variable &result, + pb_variable &result_flag) -> + ALU_divmod_gadget* { + pb_variable umod_result; umod_result.allocate(pb, "umod_result"); + pb_variable umod_flag; umod_flag.allocate(pb, "umod_flag"); + return new ALU_divmod_gadget(pb, opcode_indicators, desval, arg1val, arg2val, flag, + result, result_flag, + umod_result, umod_flag, + "ALU_divmod_gadget"); + }, + [w] (size_t des, bool f, size_t x, size_t y) -> size_t { + return (y == 0 ? 0 : x / y); + }, + [w] (size_t des, bool f, size_t x, size_t y) -> bool { + return (y == 0); + }); + print_time("udiv tests successful"); +} + +template +void test_ALU_umod_gadget(const size_t w) +{ + print_time("starting umod test"); + brute_force_arithmetic_gadget, FieldT>(w, + tinyram_opcode_UMOD, + [] (tinyram_protoboard &pb, + pb_variable_array &opcode_indicators, + word_variable_gadget &desval, + word_variable_gadget &arg1val, + word_variable_gadget &arg2val, + pb_variable &flag, + pb_variable &result, + pb_variable &result_flag) -> + ALU_divmod_gadget* { + pb_variable udiv_result; udiv_result.allocate(pb, "udiv_result"); + pb_variable udiv_flag; udiv_flag.allocate(pb, "udiv_flag"); + return new ALU_divmod_gadget(pb, opcode_indicators, desval, arg1val, arg2val, flag, + udiv_result, udiv_flag, + result, result_flag, + "ALU_divmod_gadget"); + }, + [w] (size_t des, bool f, size_t x, size_t y) -> size_t { + return (y == 0 ? 0 : x % y); + }, + [w] (size_t des, bool f, size_t x, size_t y) -> bool { + return (y == 0); + }); + print_time("umod tests successful"); +} + +template +void ALU_shr_shl_gadget::generate_r1cs_constraints() +{ + /* + select the input for barrel shifter: + + r = arg1val * opcode_indicators[SHR] + reverse(arg1val) * (1-opcode_indicators[SHR]) + r - reverse(arg1val) = (arg1val - reverse(arg1val)) * opcode_indicators[SHR] + */ + pack_reversed_input->generate_r1cs_constraints(false); + + this->pb.add_r1cs_constraint( + r1cs_constraint( + { this->arg1val.packed, reversed_input * (-1) }, + { this->opcode_indicators[tinyram_opcode_SHR] }, + { barrel_right_internal[0], reversed_input * (-1) }), + FMT(this->annotation_prefix, " select_arg1val_or_reversed")); + + /* + do logw iterations of barrel shifts + */ + for (size_t i = 0; i < logw; ++i) + { + /* assert that shifted out part is bits */ + for (size_t j = 0; j < 1ul<(this->pb, shifted_out_bits[i][j], FMT(this->annotation_prefix, " shifted_out_bits_%zu_%zu", i, j)); + } + + /* + add main shifting constraint + + + old_result = + (shifted_result * 2^(i+1) + shifted_out_part) * need_to_shift + + (shfited_result) * (1-need_to_shift) + + old_result - shifted_result = (shifted_result * (2^(i+1) - 1) + shifted_out_part) * need_to_shift + */ + linear_combination a, b, c; + + a.add_term(barrel_right_internal[i+1], (FieldT(2)^(i+1)) - FieldT::one()); + for (size_t j = 0; j < 1ul<arg2val.bits[i], 1); + + c.add_term(barrel_right_internal[i], 1); + c.add_term(barrel_right_internal[i+1], -1); + + this->pb.add_r1cs_constraint(r1cs_constraint(a, b, c), FMT(this->annotation_prefix, " barrel_shift_%zu", i)); + } + + /* + get result as the logw iterations or zero if shift was oversized + + result = (1-is_oversize_shift) * barrel_right_internal[logw] + */ + check_oversize_shift->generate_r1cs_constraints(); + this->pb.add_r1cs_constraint( + r1cs_constraint( + { ONE, is_oversize_shift * (-1) }, + { barrel_right_internal[logw] }, + { this->result }), + FMT(this->annotation_prefix, " result")); + + /* + get reversed result for SHL + */ + unpack_result->generate_r1cs_constraints(true); + pack_reversed_result->generate_r1cs_constraints(false); + + /* + select the correct output: + r = result * opcode_indicators[SHR] + reverse(result) * (1-opcode_indicators[SHR]) + r - reverse(result) = (result - reverse(result)) * opcode_indicators[SHR] + */ + this->pb.add_r1cs_constraint( + r1cs_constraint( + { this->result, reversed_result * (-1) }, + { this->opcode_indicators[tinyram_opcode_SHR] }, + { shr_result, reversed_result * (-1) }), + FMT(this->annotation_prefix, " shr_result")); + + this->pb.add_r1cs_constraint( + r1cs_constraint( + { this->result, reversed_result * (-1) }, + { this->opcode_indicators[tinyram_opcode_SHR] }, + { shr_result, reversed_result * (-1) }), + FMT(this->annotation_prefix, " shl_result")); + + this->pb.add_r1cs_constraint( + r1cs_constraint( + { ONE }, + { this->arg1val.bits[0] }, + { shr_flag }), + FMT(this->annotation_prefix, " shr_flag")); + + this->pb.add_r1cs_constraint( + r1cs_constraint( + { ONE }, + { this->arg1val.bits[this->pb.ap.w-1] }, + { shl_flag }), + FMT(this->annotation_prefix, " shl_flag")); +} + +template +void ALU_shr_shl_gadget::generate_r1cs_witness() +{ + /* select the input for barrel shifter */ + pack_reversed_input->generate_r1cs_witness_from_bits(); + + this->pb.val(barrel_right_internal[0]) = + (this->pb.val(this->opcode_indicators[tinyram_opcode_SHR]) == FieldT::one() ? + this->pb.val(this->arg1val.packed) : this->pb.val(reversed_input)); + + /* + do logw iterations of barrel shifts. + + old_result = + (shifted_result * 2^i + shifted_out_part) * need_to_shift + + (shfited_result) * (1-need_to_shift) + */ + + for (size_t i = 0; i < logw; ++i) + { + this->pb.val(barrel_right_internal[i+1]) = + (this->pb.val(this->arg2val.bits[i]) == FieldT::zero()) ? this->pb.val(barrel_right_internal[i]) : + FieldT(this->pb.val(barrel_right_internal[i]).as_ulong() >> (i+1)); + + shifted_out_bits[i].fill_with_bits_of_ulong(this->pb, this->pb.val(barrel_right_internal[i]).as_ulong() % (2u<generate_r1cs_witness(); + this->pb.val(this->result) = (FieldT::one() - this->pb.val(is_oversize_shift)) * this->pb.val(barrel_right_internal[logw]); + + /* + get reversed result for SHL + */ + unpack_result->generate_r1cs_witness_from_packed(); + pack_reversed_result->generate_r1cs_witness_from_bits(); + + /* + select the correct output: + r = result * opcode_indicators[SHR] + reverse(result) * (1-opcode_indicators[SHR]) + r - reverse(result) = (result - reverse(result)) * opcode_indicators[SHR] + */ + this->pb.val(shr_result) = (this->pb.val(this->opcode_indicators[tinyram_opcode_SHR]) == FieldT::one()) ? + this->pb.val(this->result) : this->pb.val(reversed_result); + + this->pb.val(shl_result) = this->pb.val(shr_result); + this->pb.val(shr_flag) = this->pb.val(this->arg1val.bits[0]); + this->pb.val(shl_flag) = this->pb.val(this->arg1val.bits[this->pb.ap.w-1]); +} + +template +void test_ALU_shr_gadget(const size_t w) +{ + print_time("starting shr test"); + brute_force_arithmetic_gadget, FieldT>(w, + tinyram_opcode_SHR, + [] (tinyram_protoboard &pb, + pb_variable_array &opcode_indicators, + word_variable_gadget &desval, + word_variable_gadget &arg1val, + word_variable_gadget &arg2val, + pb_variable &flag, + pb_variable &result, + pb_variable &result_flag) -> + ALU_shr_shl_gadget* { + pb_variable shl_result; shl_result.allocate(pb, "shl_result"); + pb_variable shl_flag; shl_flag.allocate(pb, "shl_flag"); + return new ALU_shr_shl_gadget(pb, opcode_indicators, desval, arg1val, arg2val, flag, + result, result_flag, + shl_result, shl_flag, + "ALU_shr_shl_gadget"); + }, + [w] (size_t des, bool f, size_t x, size_t y) -> size_t { + return (x >> y); + }, + [w] (size_t des, bool f, size_t x, size_t y) -> bool { + return (x & 1); + }); + print_time("shr tests successful"); +} + +template +void test_ALU_shl_gadget(const size_t w) +{ + print_time("starting shl test"); + brute_force_arithmetic_gadget, FieldT>(w, + tinyram_opcode_SHL, + [] (tinyram_protoboard &pb, + pb_variable_array &opcode_indicators, + word_variable_gadget &desval, + word_variable_gadget &arg1val, + word_variable_gadget &arg2val, + pb_variable &flag, + pb_variable &result, + pb_variable &result_flag) -> + ALU_shr_shl_gadget* { + pb_variable shr_result; shr_result.allocate(pb, "shr_result"); + pb_variable shr_flag; shr_flag.allocate(pb, "shr_flag"); + return new ALU_shr_shl_gadget(pb, opcode_indicators, desval, arg1val, arg2val, flag, + shr_result, shr_flag, + result, result_flag, + "ALU_shr_shl_gadget"); + }, + [w] (size_t des, bool f, size_t x, size_t y) -> size_t { + return (x << y) & ((1ul< bool { + return (x >> (w-1)); + }); + print_time("shl tests successful"); +} + +} // libsnark + +#endif diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/cpu_checkers/tinyram/components/alu_control_flow.hpp b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/cpu_checkers/tinyram/components/alu_control_flow.hpp new file mode 100644 index 0000000..9287825 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/cpu_checkers/tinyram/components/alu_control_flow.hpp @@ -0,0 +1,102 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for the TinyRAM ALU control-flow gadgets. + + These gadget check the correct execution of control-flow TinyRAM instructions. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef ALU_CONTROL_FLOW_HPP_ +#define ALU_CONTROL_FLOW_HPP_ + +#include "gadgetlib1/gadgets/cpu_checkers/tinyram/components/tinyram_protoboard.hpp" +#include "gadgetlib1/gadgets/basic_gadgets.hpp" + +namespace libsnark { + +/* control flow gadgets */ +template +class ALU_control_flow_gadget : public tinyram_standard_gadget { +public: + const word_variable_gadget pc; + const word_variable_gadget argval2; + const pb_variable flag; + const pb_variable result; + + ALU_control_flow_gadget(tinyram_protoboard &pb, + const word_variable_gadget &pc, + const word_variable_gadget &argval2, + const pb_variable &flag, + const pb_variable &result, + const std::string &annotation_prefix="") : + tinyram_standard_gadget(pb, annotation_prefix), + pc(pc), + argval2(argval2), + flag(flag), + result(result) {}; +}; + +template +class ALU_jmp_gadget : public ALU_control_flow_gadget { +public: + ALU_jmp_gadget(tinyram_protoboard &pb, + const word_variable_gadget &pc, + const word_variable_gadget &argval2, + const pb_variable &flag, + const pb_variable &result, + const std::string &annotation_prefix="") : + ALU_control_flow_gadget(pb, pc, argval2, flag, result, annotation_prefix) {} + + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +template +void test_ALU_jmp_gadget(); + +template +class ALU_cjmp_gadget : public ALU_control_flow_gadget { +public: + ALU_cjmp_gadget(tinyram_protoboard &pb, + const word_variable_gadget &pc, + const word_variable_gadget &argval2, + const pb_variable &flag, + const pb_variable &result, + const std::string &annotation_prefix="") : + ALU_control_flow_gadget(pb, pc, argval2, flag, result, annotation_prefix) {} + + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +template +void test_ALU_cjmp_gadget(); + +template +class ALU_cnjmp_gadget : public ALU_control_flow_gadget { +public: + ALU_cnjmp_gadget(tinyram_protoboard &pb, + const word_variable_gadget &pc, + const word_variable_gadget &argval2, + const pb_variable &flag, + const pb_variable &result, + const std::string &annotation_prefix="") : + ALU_control_flow_gadget(pb, pc, argval2, flag, result, annotation_prefix) {} + + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +template +void test_ALU_cnjmp_gadget(); + +} // libsnark + +#include "gadgetlib1/gadgets/cpu_checkers/tinyram/components/alu_control_flow.tcc" + +#endif // ALU_CONTROL_FLOW_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/cpu_checkers/tinyram/components/alu_control_flow.tcc b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/cpu_checkers/tinyram/components/alu_control_flow.tcc new file mode 100644 index 0000000..606d0b2 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/cpu_checkers/tinyram/components/alu_control_flow.tcc @@ -0,0 +1,233 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for the TinyRAM ALU control-flow gadgets. + + See alu_control_flow.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef ALU_CONTROL_FLOW_TCC_ +#define ALU_CONTROL_FLOW_TCC_ + +#include "common/profiling.hpp" + +namespace libsnark { + +/* jmp */ +template +void ALU_jmp_gadget::generate_r1cs_constraints() +{ + this->pb.add_r1cs_constraint( + r1cs_constraint( + { ONE }, + { this->argval2.packed }, + { this->result }), + FMT(this->annotation_prefix, " jmp_result")); +} + +template +void ALU_jmp_gadget::generate_r1cs_witness() +{ + this->pb.val(this->result) = this->pb.val(this->argval2.packed); +} + +template +void test_ALU_jmp_gadget() +{ + print_time("starting jmp test"); + + tinyram_architecture_params ap(16, 16); + tinyram_program P; P.instructions = generate_tinyram_prelude(ap); + tinyram_protoboard pb(ap, P.size(), 0, 10); + + word_variable_gadget pc(pb, "pc"), argval2(pb, "argval2"); + pb_variable flag, result; + + pc.generate_r1cs_constraints(true); + argval2.generate_r1cs_constraints(true); + flag.allocate(pb, "flag"); + result.allocate(pb, "result"); + + ALU_jmp_gadget jmp(pb, pc, argval2, flag, result, "jmp"); + jmp.generate_r1cs_constraints(); + + pb.val(argval2.packed) = FieldT(123); + argval2.generate_r1cs_witness_from_packed(); + + jmp.generate_r1cs_witness(); + + assert(pb.val(result) == FieldT(123)); + assert(pb.is_satisfied()); + print_time("positive jmp test successful"); + + pb.val(result) = FieldT(1); + assert(!pb.is_satisfied()); + print_time("negative jmp test successful"); +} + +/* cjmp */ +template +void ALU_cjmp_gadget::generate_r1cs_constraints() +{ + /* + flag1 * argval2 + (1-flag1) * (pc1 + 1) = cjmp_result + flag1 * (argval2 - pc1 - 1) = cjmp_result - pc1 - 1 + + Note that instruction fetch semantics require program counter to + be aligned to the double word by rounding down, and pc_addr in + the outer reduction is expressed as a double word address. To + achieve this we just discard the first ap.subaddr_len() bits of + the byte address of the PC. + */ + this->pb.add_r1cs_constraint( + r1cs_constraint( + this->flag, + pb_packing_sum(pb_variable_array(this->argval2.bits.begin() + this->pb.ap.subaddr_len(), this->argval2.bits.end())) - this->pc.packed - 1, + this->result - this->pc.packed - 1), + FMT(this->annotation_prefix, " cjmp_result")); +} + +template +void ALU_cjmp_gadget::generate_r1cs_witness() +{ + this->pb.val(this->result) = ((this->pb.val(this->flag) == FieldT::one()) ? + FieldT(this->pb.val(this->argval2.packed).as_ulong() >> this->pb.ap.subaddr_len()) : + this->pb.val(this->pc.packed) + FieldT::one()); +} + +template +void test_ALU_cjmp_gadget() +{ + // TODO: update + print_time("starting cjmp test"); + + tinyram_architecture_params ap(16, 16); + tinyram_program P; P.instructions = generate_tinyram_prelude(ap); + tinyram_protoboard pb(ap, P.size(), 0, 10); + + word_variable_gadget pc(pb, "pc"), argval2(pb, "argval2"); + pb_variable flag, result; + + pc.generate_r1cs_constraints(true); + argval2.generate_r1cs_constraints(true); + flag.allocate(pb, "flag"); + result.allocate(pb, "result"); + + ALU_cjmp_gadget cjmp(pb, pc, argval2, flag, result, "cjmp"); + cjmp.generate_r1cs_constraints(); + + pb.val(argval2.packed) = FieldT(123); + argval2.generate_r1cs_witness_from_packed(); + pb.val(pc.packed) = FieldT(456); + pc.generate_r1cs_witness_from_packed(); + + pb.val(flag) = FieldT(1); + cjmp.generate_r1cs_witness(); + + assert(pb.val(result) == FieldT(123)); + assert(pb.is_satisfied()); + print_time("positive cjmp test successful"); + + pb.val(flag) = FieldT(0); + assert(!pb.is_satisfied()); + print_time("negative cjmp test successful"); + + pb.val(flag) = FieldT(0); + cjmp.generate_r1cs_witness(); + + assert(pb.val(result) == FieldT(456+2*ap.w/8)); + assert(pb.is_satisfied()); + print_time("positive cjmp test successful"); + + pb.val(flag) = FieldT(1); + assert(!pb.is_satisfied()); + print_time("negative cjmp test successful"); +} + +/* cnjmp */ +template +void ALU_cnjmp_gadget::generate_r1cs_constraints() +{ + /* + flag1 * (pc1 + inc) + (1-flag1) * argval2 = cnjmp_result + flag1 * (pc1 + inc - argval2) = cnjmp_result - argval2 + + Note that instruction fetch semantics require program counter to + be aligned to the double word by rounding down, and pc_addr in + the outer reduction is expressed as a double word address. To + achieve this we just discard the first ap.subaddr_len() bits of + the byte address of the PC. + */ + this->pb.add_r1cs_constraint( + r1cs_constraint( + this->flag, + this->pc.packed + 1 - pb_packing_sum(pb_variable_array(this->argval2.bits.begin() + this->pb.ap.subaddr_len(), this->argval2.bits.end())), + this->result - pb_packing_sum(pb_variable_array(this->argval2.bits.begin() + this->pb.ap.subaddr_len(), this->argval2.bits.end()))), + FMT(this->annotation_prefix, " cnjmp_result")); +} + +template +void ALU_cnjmp_gadget::generate_r1cs_witness() +{ + this->pb.val(this->result) = ((this->pb.val(this->flag) == FieldT::one()) ? + this->pb.val(this->pc.packed) + FieldT::one() : + FieldT(this->pb.val(this->argval2.packed).as_ulong() >> this->pb.ap.subaddr_len())); +} + +template +void test_ALU_cnjmp_gadget() +{ + // TODO: update + print_time("starting cnjmp test"); + + tinyram_architecture_params ap(16, 16); + tinyram_program P; P.instructions = generate_tinyram_prelude(ap); + tinyram_protoboard pb(ap, P.size(), 0, 10); + + word_variable_gadget pc(pb, "pc"), argval2(pb, "argval2"); + pb_variable flag, result; + + pc.generate_r1cs_constraints(true); + argval2.generate_r1cs_constraints(true); + flag.allocate(pb, "flag"); + result.allocate(pb, "result"); + + ALU_cnjmp_gadget cnjmp(pb, pc, argval2, flag, result, "cjmp"); + cnjmp.generate_r1cs_constraints(); + + pb.val(argval2.packed) = FieldT(123); + argval2.generate_r1cs_witness_from_packed(); + pb.val(pc.packed) = FieldT(456); + pc.generate_r1cs_witness_from_packed(); + + pb.val(flag) = FieldT(0); + cnjmp.generate_r1cs_witness(); + + assert(pb.val(result) == FieldT(123)); + assert(pb.is_satisfied()); + print_time("positive cnjmp test successful"); + + pb.val(flag) = FieldT(1); + assert(!pb.is_satisfied()); + print_time("negative cnjmp test successful"); + + pb.val(flag) = FieldT(1); + cnjmp.generate_r1cs_witness(); + + assert(pb.val(result) == FieldT(456 + (2*pb.ap.w/8))); + assert(pb.is_satisfied()); + print_time("positive cnjmp test successful"); + + pb.val(flag) = FieldT(0); + assert(!pb.is_satisfied()); + print_time("negative cnjmp test successful"); +} + +} // libsnark + +#endif // ALU_CONTROL_FLOW_TCC_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/cpu_checkers/tinyram/components/alu_gadget.hpp b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/cpu_checkers/tinyram/components/alu_gadget.hpp new file mode 100644 index 0000000..8466fe0 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/cpu_checkers/tinyram/components/alu_gadget.hpp @@ -0,0 +1,183 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for the TinyRAM ALU gadget. + + The gadget checks the correct execution of a given TinyRAM instruction. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef ALU_GADGET_HPP_ +#define ALU_GADGET_HPP_ + +#include "gadgetlib1/gadgets/cpu_checkers/tinyram/components/alu_arithmetic.hpp" +#include "gadgetlib1/gadgets/cpu_checkers/tinyram/components/alu_control_flow.hpp" + +namespace libsnark { + +template +class ALU_gadget : public tinyram_standard_gadget { +private: + std::vector > > components; +public: + pb_variable_array opcode_indicators; + word_variable_gadget pc; + word_variable_gadget desval; + word_variable_gadget arg1val; + word_variable_gadget arg2val; + pb_variable flag; + pb_variable_array instruction_results; + pb_variable_array instruction_flags; + + ALU_gadget(tinyram_protoboard &pb, + const pb_variable_array &opcode_indicators, + const word_variable_gadget &pc, + const word_variable_gadget &desval, + const word_variable_gadget &arg1val, + const word_variable_gadget &arg2val, + const pb_variable &flag, + const pb_variable_array &instruction_results, + const pb_variable_array &instruction_flags, + const std::string &annotation_prefix="") : + tinyram_standard_gadget(pb, annotation_prefix), + opcode_indicators(opcode_indicators), + pc(pc), + desval(desval), + arg1val(arg1val), + arg2val(arg2val), + flag(flag), + instruction_results(instruction_results), + instruction_flags(instruction_flags) + { + components.resize(1ul<(pb, opcode_indicators, desval, arg1val, arg2val, flag, + instruction_results[tinyram_opcode_AND], + instruction_flags[tinyram_opcode_AND], + FMT(this->annotation_prefix, " AND"))); + + components[tinyram_opcode_OR].reset( + new ALU_or_gadget(pb, opcode_indicators, desval, arg1val, arg2val, flag, + instruction_results[tinyram_opcode_OR], + instruction_flags[tinyram_opcode_OR], + FMT(this->annotation_prefix, " OR"))); + + components[tinyram_opcode_XOR].reset( + new ALU_xor_gadget(pb, opcode_indicators, desval, arg1val, arg2val, flag, + instruction_results[tinyram_opcode_XOR], + instruction_flags[tinyram_opcode_XOR], + FMT(this->annotation_prefix, " XOR"))); + + components[tinyram_opcode_NOT].reset( + new ALU_not_gadget(pb, opcode_indicators, desval, arg1val, arg2val, flag, + instruction_results[tinyram_opcode_NOT], + instruction_flags[tinyram_opcode_NOT], + FMT(this->annotation_prefix, " NOT"))); + + components[tinyram_opcode_ADD].reset( + new ALU_add_gadget(pb, opcode_indicators, desval, arg1val, arg2val, flag, + instruction_results[tinyram_opcode_ADD], + instruction_flags[tinyram_opcode_ADD], + FMT(this->annotation_prefix, " ADD"))); + + components[tinyram_opcode_SUB].reset( + new ALU_sub_gadget(pb, opcode_indicators, desval, arg1val, arg2val, flag, + instruction_results[tinyram_opcode_SUB], + instruction_flags[tinyram_opcode_SUB], + FMT(this->annotation_prefix, " SUB"))); + + components[tinyram_opcode_MOV].reset( + new ALU_mov_gadget(pb, opcode_indicators, desval, arg1val, arg2val, flag, + instruction_results[tinyram_opcode_MOV], + instruction_flags[tinyram_opcode_MOV], + FMT(this->annotation_prefix, " MOV"))); + + components[tinyram_opcode_CMOV].reset( + new ALU_cmov_gadget(pb, opcode_indicators, desval, arg1val, arg2val, flag, + instruction_results[tinyram_opcode_CMOV], + instruction_flags[tinyram_opcode_CMOV], + FMT(this->annotation_prefix, " CMOV"))); + + components[tinyram_opcode_CMPA].reset( + new ALU_cmp_gadget(pb, opcode_indicators, desval, arg1val, arg2val, flag, + instruction_results[tinyram_opcode_CMPE], + instruction_flags[tinyram_opcode_CMPE], + instruction_results[tinyram_opcode_CMPA], + instruction_flags[tinyram_opcode_CMPA], + instruction_results[tinyram_opcode_CMPAE], + instruction_flags[tinyram_opcode_CMPAE], + FMT(this->annotation_prefix, " CMP_unsigned"))); + + components[tinyram_opcode_CMPG].reset( + new ALU_cmps_gadget(pb, opcode_indicators, desval, arg1val, arg2val, flag, + instruction_results[tinyram_opcode_CMPG], + instruction_flags[tinyram_opcode_CMPG], + instruction_results[tinyram_opcode_CMPGE], + instruction_flags[tinyram_opcode_CMPGE], + FMT(this->annotation_prefix, " CMP_signed"))); + + components[tinyram_opcode_UMULH].reset( + new ALU_umul_gadget(pb, opcode_indicators, desval, arg1val, arg2val, flag, + instruction_results[tinyram_opcode_MULL], + instruction_flags[tinyram_opcode_MULL], + instruction_results[tinyram_opcode_UMULH], + instruction_flags[tinyram_opcode_UMULH], + FMT(this->annotation_prefix, " MUL_unsigned"))); + + components[tinyram_opcode_SMULH].reset( + new ALU_smul_gadget(pb, opcode_indicators, desval, arg1val, arg2val, flag, + instruction_results[tinyram_opcode_SMULH], + instruction_flags[tinyram_opcode_SMULH], + FMT(this->annotation_prefix, " MUL_signed"))); + + + components[tinyram_opcode_UDIV].reset( + new ALU_divmod_gadget(pb, opcode_indicators, desval, arg1val, arg2val, flag, + instruction_results[tinyram_opcode_UDIV], + instruction_flags[tinyram_opcode_UDIV], + instruction_results[tinyram_opcode_UMOD], + instruction_flags[tinyram_opcode_UMOD], + FMT(this->annotation_prefix, " DIV"))); + + components[tinyram_opcode_SHR].reset( + new ALU_shr_shl_gadget(pb, opcode_indicators, desval, arg1val, arg2val, flag, + instruction_results[tinyram_opcode_SHR], + instruction_flags[tinyram_opcode_SHR], + instruction_results[tinyram_opcode_SHL], + instruction_flags[tinyram_opcode_SHL], + FMT(this->annotation_prefix, " SHR_SHL"))); + + /* control flow */ + components[tinyram_opcode_JMP].reset( + new ALU_jmp_gadget(pb, pc, arg2val, flag, + instruction_results[tinyram_opcode_JMP], + FMT(this->annotation_prefix, " JMP"))); + + components[tinyram_opcode_CJMP].reset( + new ALU_cjmp_gadget(pb, pc, arg2val, flag, + instruction_results[tinyram_opcode_CJMP], + FMT(this->annotation_prefix, " CJMP"))); + + components[tinyram_opcode_CNJMP].reset( + new ALU_cnjmp_gadget(pb, pc, arg2val, flag, + instruction_results[tinyram_opcode_CNJMP], + FMT(this->annotation_prefix, " CNJMP"))); + } + + void generate_r1cs_constraints(); + + void generate_r1cs_witness(); + +}; + +} // libsnark + +#include "gadgetlib1/gadgets/cpu_checkers/tinyram/components/alu_gadget.tcc" + +#endif // ALU_GADGET_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/cpu_checkers/tinyram/components/alu_gadget.tcc b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/cpu_checkers/tinyram/components/alu_gadget.tcc new file mode 100644 index 0000000..b5826a6 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/cpu_checkers/tinyram/components/alu_gadget.tcc @@ -0,0 +1,45 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for the TinyRAM ALU gadget. + + See alu.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef ALU_GADGET_TCC_ +#define ALU_GADGET_TCC_ + +namespace libsnark { + +template +void ALU_gadget::generate_r1cs_constraints() +{ + for (size_t i = 0; i < 1ul<pb.ap.opcode_width(); ++i) + { + if (components[i]) + { + components[i]->generate_r1cs_constraints(); + } + } +} + +template +void ALU_gadget::generate_r1cs_witness() +{ + for (size_t i = 0; i < 1ul<pb.ap.opcode_width(); ++i) + { + if (components[i]) + { + components[i]->generate_r1cs_witness(); + } + } +} + +} // libsnark + +#endif // ALU_GADGET_TCC_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/cpu_checkers/tinyram/components/argument_decoder_gadget.hpp b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/cpu_checkers/tinyram/components/argument_decoder_gadget.hpp new file mode 100644 index 0000000..5f6f0e8 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/cpu_checkers/tinyram/components/argument_decoder_gadget.hpp @@ -0,0 +1,66 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for the TinyRAM argument decoder gadget. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef ARGUMENT_DECODER_GADGET_HPP_ +#define ARGUMENT_DECODER_GADGET_HPP_ + +namespace libsnark { + +template +class argument_decoder_gadget : public tinyram_standard_gadget { +private: + pb_variable packed_desidx; + pb_variable packed_arg1idx; + pb_variable packed_arg2idx; + + std::shared_ptr > pack_desidx; + std::shared_ptr > pack_arg1idx; + std::shared_ptr > pack_arg2idx; + + pb_variable arg2_demux_result; + pb_variable arg2_demux_success; + + std::shared_ptr > demux_des; + std::shared_ptr > demux_arg1; + std::shared_ptr > demux_arg2; +public: + pb_variable arg2_is_imm; + pb_variable_array desidx; + pb_variable_array arg1idx; + pb_variable_array arg2idx; + pb_variable_array packed_registers; + pb_variable packed_desval; + pb_variable packed_arg1val; + pb_variable packed_arg2val; + + argument_decoder_gadget(tinyram_protoboard &pb, + const pb_variable &arg2_is_imm, + const pb_variable_array &desidx, + const pb_variable_array &arg1idx, + const pb_variable_array &arg2idx, + const pb_variable_array &packed_registers, + const pb_variable &packed_desval, + const pb_variable &packed_arg1val, + const pb_variable &packed_arg2val, + const std::string &annotation_prefix=""); + + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +template +void test_argument_decoder_gadget(); + +} // libsnark + +#include "gadgetlib1/gadgets/cpu_checkers/tinyram/components/argument_decoder_gadget.tcc" + +#endif // ARGUMENT_DECODER_GADGET_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/cpu_checkers/tinyram/components/argument_decoder_gadget.tcc b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/cpu_checkers/tinyram/components/argument_decoder_gadget.tcc new file mode 100644 index 0000000..ecaa8e5 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/cpu_checkers/tinyram/components/argument_decoder_gadget.tcc @@ -0,0 +1,187 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for the TinyRAM argument decoder gadget. + + See argument_decoder_gadget.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef ARGUMENT_DECODER_GADGET_TCC_ +#define ARGUMENT_DECODER_GADGET_TCC_ + +namespace libsnark { + +template +argument_decoder_gadget::argument_decoder_gadget(tinyram_protoboard &pb, + const pb_variable &arg2_is_imm, + const pb_variable_array &desidx, + const pb_variable_array &arg1idx, + const pb_variable_array &arg2idx, + const pb_variable_array &packed_registers, + const pb_variable &packed_desval, + const pb_variable &packed_arg1val, + const pb_variable &packed_arg2val, + const std::string &annotation_prefix) : + tinyram_standard_gadget(pb, annotation_prefix), + arg2_is_imm(arg2_is_imm), + desidx(desidx), + arg1idx(arg1idx), + arg2idx(arg2idx), + packed_registers(packed_registers), + packed_desval(packed_desval), + packed_arg1val(packed_arg1val), + packed_arg2val(packed_arg2val) +{ + assert(desidx.size() == pb.ap.reg_arg_width()); + assert(arg1idx.size() == pb.ap.reg_arg_width()); + assert(arg2idx.size() == pb.ap.reg_arg_or_imm_width()); + + /* decode accordingly */ + packed_desidx.allocate(pb, FMT(this->annotation_prefix, " packed_desidx")); + packed_arg1idx.allocate(pb, FMT(this->annotation_prefix, " packed_arg1idx")); + packed_arg2idx.allocate(pb, FMT(this->annotation_prefix, " packed_arg2idx")); + + pack_desidx.reset(new packing_gadget(pb, desidx, packed_desidx, FMT(this->annotation_prefix, "pack_desidx"))); + pack_arg1idx.reset(new packing_gadget(pb, arg1idx, packed_arg1idx, FMT(this->annotation_prefix, "pack_arg1idx"))); + pack_arg2idx.reset(new packing_gadget(pb, arg2idx, packed_arg2idx, FMT(this->annotation_prefix, "pack_arg2idx"))); + + arg2_demux_result.allocate(pb, FMT(this->annotation_prefix, " arg2_demux_result")); + arg2_demux_success.allocate(pb, FMT(this->annotation_prefix, " arg2_demux_success")); + + demux_des.reset( + new loose_multiplexing_gadget(pb, packed_registers, packed_desidx, packed_desval, ONE, + FMT(this->annotation_prefix, " demux_des"))); + demux_arg1.reset( + new loose_multiplexing_gadget(pb, packed_registers, packed_arg1idx, packed_arg1val, ONE, + FMT(this->annotation_prefix, " demux_arg1"))); + demux_arg2.reset( + new loose_multiplexing_gadget(pb, packed_registers, packed_arg2idx, arg2_demux_result, arg2_demux_success, + FMT(this->annotation_prefix, " demux_arg2"))); +} + +template +void argument_decoder_gadget::generate_r1cs_constraints() +{ + /* pack */ + pack_desidx->generate_r1cs_constraints(true); + pack_arg1idx->generate_r1cs_constraints(true); + pack_arg2idx->generate_r1cs_constraints(true); + + /* demux */ + demux_des->generate_r1cs_constraints(); + demux_arg1->generate_r1cs_constraints(); + demux_arg2->generate_r1cs_constraints(); + + /* enforce correct handling of arg2val */ + + /* it is false that arg2 is reg and demux failed: + (1 - arg2_is_imm) * (1 - arg2_demux_success) = 0 */ + this->pb.add_r1cs_constraint( + r1cs_constraint({ ONE, arg2_is_imm * (-1) }, + { ONE, arg2_demux_success * (-1) }, + { ONE * 0 }), + FMT(this->annotation_prefix, " ensure_correc_demux")); + + /* + arg2val = arg2_is_imm * packed_arg2idx + + (1 - arg2_is_imm) * arg2_demux_result + + arg2val - arg2_demux_result = arg2_is_imm * (packed_arg2idx - arg2_demux_result) + */ + this->pb.add_r1cs_constraint( + r1cs_constraint({ arg2_is_imm }, + { packed_arg2idx, arg2_demux_result * (-1) }, + { packed_arg2val, arg2_demux_result * (-1) }), + FMT(this->annotation_prefix, " compute_arg2val")); +} + +template +void argument_decoder_gadget::generate_r1cs_witness() +{ + /* pack */ + pack_desidx->generate_r1cs_witness_from_bits(); + pack_arg1idx->generate_r1cs_witness_from_bits(); + pack_arg2idx->generate_r1cs_witness_from_bits(); + + /* demux */ + demux_des->generate_r1cs_witness(); + demux_arg1->generate_r1cs_witness(); + demux_arg2->generate_r1cs_witness(); + + /* handle arg2val */ + this->pb.val(packed_arg2val) = + (this->pb.val(arg2_is_imm) == FieldT::one() ? + this->pb.val(packed_arg2idx) : this->pb.val(arg2_demux_result)); +} + +template +void test_argument_decoder_gadget() +{ + print_time("starting argument_decoder_gadget test"); + + tinyram_architecture_params ap(16, 16); + tinyram_program P; P.instructions = generate_tinyram_prelude(ap); + tinyram_protoboard pb(ap, P.size(), 0, 10); + + pb_variable_array packed_registers; + packed_registers.allocate(pb, ap.k, "packed_registers"); + + pb_variable arg2_is_imm; + arg2_is_imm.allocate(pb, "arg_is_imm"); + + dual_variable_gadget desidx(pb, ap.reg_arg_width(), "desidx"); + dual_variable_gadget arg1idx(pb, ap.reg_arg_width(), "arg1idx"); + dual_variable_gadget arg2idx(pb, ap.reg_arg_or_imm_width(), "arg2idx"); + + pb_variable packed_desval, packed_arg1val, packed_arg2val; + packed_desval.allocate(pb, "packed_desval"); + packed_arg1val.allocate(pb, "packed_arg1val"); + packed_arg2val.allocate(pb, "packed_arg2val"); + + argument_decoder_gadget g(pb, packed_registers, arg2_is_imm, + desidx.bits, arg1idx.bits, arg2idx.bits, + packed_desval, packed_arg1val, packed_arg2val, "g"); + + g.generate_r1cs_constraints(); + for (size_t i = 0; i < ap.k; ++i) + { + pb.val(packed_registers[i]) = FieldT(1000+i); + } + + pb.val(desidx.packed) = FieldT(2); + pb.val(arg1idx.packed) = FieldT(5); + pb.val(arg2idx.packed) = FieldT(7); + pb.val(arg2_is_imm) = FieldT::zero(); + + desidx.generate_r1cs_witness_from_packed(); + arg1idx.generate_r1cs_witness_from_packed(); + arg2idx.generate_r1cs_witness_from_packed(); + + g.generate_r1cs_witness(); + + assert(pb.val(packed_desval) == FieldT(1002)); + assert(pb.val(packed_arg1val) == FieldT(1005)); + assert(pb.val(packed_arg2val) == FieldT(1007)); + assert(pb.is_satisfied()); + printf("positive test (get reg) successful\n"); + + pb.val(arg2_is_imm) = FieldT::one(); + g.generate_r1cs_witness(); + + assert(pb.val(packed_desval) == FieldT(1002)); + assert(pb.val(packed_arg1val) == FieldT(1005)); + assert(pb.val(packed_arg2val) == FieldT(7)); + assert(pb.is_satisfied()); + printf("positive test (get imm) successful\n"); + + print_time("argument_decoder_gadget tests successful"); +} + +} // libsnark + +#endif // ARGUMENT_DECODER_GADGET_TCC_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/cpu_checkers/tinyram/components/consistency_enforcer_gadget.hpp b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/cpu_checkers/tinyram/components/consistency_enforcer_gadget.hpp new file mode 100644 index 0000000..fdf6c0a --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/cpu_checkers/tinyram/components/consistency_enforcer_gadget.hpp @@ -0,0 +1,71 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for the TinyRAM consistency enforcer gadget. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef CONSISTENCY_ENFORCER_GADGET_HPP_ +#define CONSISTENCY_ENFORCER_GADGET_HPP_ + +namespace libsnark { + +template +class consistency_enforcer_gadget : public tinyram_standard_gadget { +private: + pb_variable is_register_instruction; + pb_variable is_control_flow_instruction; + pb_variable is_stall_instruction; + + pb_variable packed_desidx; + std::shared_ptr > pack_desidx; + + pb_variable computed_result; + pb_variable computed_flag; + std::shared_ptr > compute_computed_result; + std::shared_ptr > compute_computed_flag; + + pb_variable pc_from_cf_or_zero; + + std::shared_ptr > demux_packed_outgoing_desval; +public: + pb_variable_array opcode_indicators; + pb_variable_array instruction_results; + pb_variable_array instruction_flags; + pb_variable_array desidx; + pb_variable packed_incoming_pc; + pb_variable_array packed_incoming_registers; + pb_variable packed_incoming_desval; + pb_variable incoming_flag; + pb_variable packed_outgoing_pc; + pb_variable_array packed_outgoing_registers; + pb_variable outgoing_flag; + pb_variable packed_outgoing_desval; + + consistency_enforcer_gadget(tinyram_protoboard &pb, + const pb_variable_array &opcode_indicators, + const pb_variable_array &instruction_results, + const pb_variable_array &instruction_flags, + const pb_variable_array &desidx, + const pb_variable &packed_incoming_pc, + const pb_variable_array &packed_incoming_registers, + const pb_variable &packed_incoming_desval, + const pb_variable &incoming_flag, + const pb_variable &packed_outgoing_pc, + const pb_variable_array &packed_outgoing_registers, + const pb_variable &outgoing_flag, + const std::string &annotation_prefix=""); + + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +} // libsnark + +#include "gadgetlib1/gadgets/cpu_checkers/tinyram/components/consistency_enforcer_gadget.tcc" + +#endif // CONSISTENCY_ENFORCER_GADGET_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/cpu_checkers/tinyram/components/consistency_enforcer_gadget.tcc b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/cpu_checkers/tinyram/components/consistency_enforcer_gadget.tcc new file mode 100644 index 0000000..9da062e --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/cpu_checkers/tinyram/components/consistency_enforcer_gadget.tcc @@ -0,0 +1,604 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for the TinyRAM consistency enforcer gadget. + + See consistency_enforcer_gadget.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef CONSISTENCY_ENFORCER_GADGET_TCC_ +#define CONSISTENCY_ENFORCER_GADGET_TCC_ + +namespace libsnark { + +template +consistency_enforcer_gadget::consistency_enforcer_gadget(tinyram_protoboard &pb, + const pb_variable_array &opcode_indicators, + const pb_variable_array &instruction_results, + const pb_variable_array &instruction_flags, + const pb_variable_array &desidx, + const pb_variable &packed_incoming_pc, + const pb_variable_array &packed_incoming_registers, + const pb_variable &packed_incoming_desval, + const pb_variable &incoming_flag, + const pb_variable &packed_outgoing_pc, + const pb_variable_array &packed_outgoing_registers, + const pb_variable &outgoing_flag, + const std::string &annotation_prefix) : + tinyram_standard_gadget(pb, annotation_prefix), + opcode_indicators(opcode_indicators), + instruction_results(instruction_results), + instruction_flags(instruction_flags), + desidx(desidx), + packed_incoming_pc(packed_incoming_pc), + packed_incoming_registers(packed_incoming_registers), + packed_incoming_desval(packed_incoming_desval), + incoming_flag(incoming_flag), + packed_outgoing_pc(packed_outgoing_pc), + packed_outgoing_registers(packed_outgoing_registers), + outgoing_flag(outgoing_flag) +{ + assert(desidx.size() == pb.ap.reg_arg_width()); + + packed_outgoing_desval.allocate(pb, FMT(this->annotation_prefix, " packed_outgoing_desval")); + is_register_instruction.allocate(pb, FMT(this->annotation_prefix, " is_register_instruction")); + is_control_flow_instruction.allocate(pb, FMT(this->annotation_prefix, " is_control_flow_instruction")); + is_stall_instruction.allocate(pb, FMT(this->annotation_prefix, " is_stall_instruction")); + + packed_desidx.allocate(pb, FMT(this->annotation_prefix, " packed_desidx")); + pack_desidx.reset(new packing_gadget(pb, desidx, packed_desidx, FMT(this->annotation_prefix, "pack_desidx"))); + + computed_result.allocate(pb, FMT(this->annotation_prefix, " computed_result")); + computed_flag.allocate(pb, FMT(this->annotation_prefix, " computed_flag")); + + compute_computed_result.reset( + new inner_product_gadget(pb, opcode_indicators, instruction_results, computed_result, + FMT(this->annotation_prefix, " compute_computed_result"))); + compute_computed_flag.reset( + new inner_product_gadget(pb, opcode_indicators, instruction_flags, computed_flag, + FMT(this->annotation_prefix, " compute_computed_flag"))); + + pc_from_cf_or_zero.allocate(pb, FMT(this->annotation_prefix, " pc_from_cf_or_zero")); + + demux_packed_outgoing_desval.reset( + new loose_multiplexing_gadget(pb, packed_outgoing_registers, packed_desidx, packed_outgoing_desval, ONE, + FMT(this->annotation_prefix, " demux_packed_outgoing_desval"))); + +} + +template +void consistency_enforcer_gadget::generate_r1cs_constraints() +{ + /* pack destination index */ + pack_desidx->generate_r1cs_constraints(false); + + /* demux result register */ + demux_packed_outgoing_desval->generate_r1cs_constraints(); + + /* is_register_instruction */ + linear_combination reg_a, reg_b, reg_c; + reg_a.add_term(ONE, 1); + for (size_t i = 0; i < ARRAY_SIZE(tinyram_opcodes_register); ++i) + { + reg_b.add_term(opcode_indicators[tinyram_opcodes_register[i]], 1); + } + reg_c.add_term(is_register_instruction, 1); + this->pb.add_r1cs_constraint(r1cs_constraint(reg_a, reg_b, reg_c), FMT(this->annotation_prefix, " is_register_instruction")); + + /* is_control_flow_instruction */ + linear_combination cf_a, cf_b, cf_c; + cf_a.add_term(ONE, 1); + for (size_t i = 0; i < ARRAY_SIZE(tinyram_opcodes_control_flow); ++i) + { + cf_b.add_term(opcode_indicators[tinyram_opcodes_control_flow[i]], 1); + } + cf_c.add_term(is_control_flow_instruction, 1); + this->pb.add_r1cs_constraint(r1cs_constraint(cf_a, cf_b, cf_c), FMT(this->annotation_prefix, " is_control_flow_instruction")); + + /* is_stall_instruction */ + linear_combination stall_a, stall_b, stall_c; + stall_a.add_term(ONE, 1); + for (size_t i = 0; i < ARRAY_SIZE(tinyram_opcodes_stall); ++i) + { + stall_b.add_term(opcode_indicators[tinyram_opcodes_stall[i]], 1); + } + stall_c.add_term(is_stall_instruction, 1); + this->pb.add_r1cs_constraint(r1cs_constraint(stall_a, stall_b, stall_c), FMT(this->annotation_prefix, " is_stall_instruction")); + + /* compute actual result/actual flag */ + compute_computed_result->generate_r1cs_constraints(); + compute_computed_flag->generate_r1cs_constraints(); + + /* + compute new PC address (in double words, not bytes!): + + PC' = computed_result * is_control_flow_instruction + PC * is_stall_instruction + (PC+1) * (1-is_control_flow_instruction - is_stall_instruction) + PC' - pc_from_cf_or_zero - (1-is_control_flow_instruction - is_stall_instruction) = PC * (1 - is_control_flow_instruction) + */ + this->pb.add_r1cs_constraint( + r1cs_constraint( + computed_result, + is_control_flow_instruction, + pc_from_cf_or_zero), + FMT(this->annotation_prefix, " pc_from_cf_or_zero")); + + this->pb.add_r1cs_constraint( + r1cs_constraint( + packed_incoming_pc, + 1 - is_control_flow_instruction, + packed_outgoing_pc - pc_from_cf_or_zero - (1 - is_control_flow_instruction - is_stall_instruction)), + FMT(this->annotation_prefix, " packed_outgoing_pc")); + + /* + enforce new flag: + + flag' = computed_flag * is_register_instruction + flag * (1-is_register_instruction) + flag' - flag = (computed_flag - flag) * is_register_instruction + */ + this->pb.add_r1cs_constraint( + r1cs_constraint( + { computed_flag, incoming_flag * (-1) }, + { is_register_instruction }, + { outgoing_flag, incoming_flag * (-1) }), + FMT(this->annotation_prefix, " outgoing_flag")); + + /* + force carryover of unchanged registers + + (1-indicator) * (new-old) = 0 + + In order to save constraints we "borrow" indicator variables + from loose multiplexing gadget. + */ + for (size_t i = 0; i < this->pb.ap.k; ++i) + { + this->pb.add_r1cs_constraint( + r1cs_constraint( + { ONE, demux_packed_outgoing_desval->alpha[i] * (-1) }, + { packed_outgoing_registers[i], packed_incoming_registers[i] * (-1) }, + { ONE * 0 }), + FMT(this->annotation_prefix, " register_carryover_%zu", i)); + } + + /* + enforce correct destination register value: + + next_desval = computed_result * is_register_instruction + packed_incoming_desval * (1-is_register_instruction) + next_desval - packed_incoming_desval = (computed_result - packed_incoming_desval) * is_register_instruction + */ + this->pb.add_r1cs_constraint( + r1cs_constraint( + { computed_result, packed_incoming_desval * (-1) }, + { is_register_instruction }, + { packed_outgoing_desval, packed_incoming_desval * (-1) }), + FMT(this->annotation_prefix, " packed_outgoing_desval")); +} + +template +void consistency_enforcer_gadget::generate_r1cs_witness() +{ + /* pack destination index */ + pack_desidx->generate_r1cs_witness_from_bits(); + + /* is_register_instruction */ + this->pb.val(is_register_instruction) = FieldT::zero(); + + for (size_t i = 0; i < ARRAY_SIZE(tinyram_opcodes_register); ++i) + { + this->pb.val(is_register_instruction) += this->pb.val(opcode_indicators[tinyram_opcodes_register[i]]); + } + + /* is_control_flow_instruction */ + this->pb.val(is_control_flow_instruction) = FieldT::zero(); + + for (size_t i = 0; i < ARRAY_SIZE(tinyram_opcodes_control_flow); ++i) + { + this->pb.val(is_control_flow_instruction) += this->pb.val(opcode_indicators[tinyram_opcodes_control_flow[i]]); + } + + /* is_stall_instruction */ + this->pb.val(is_stall_instruction) = FieldT::zero(); + + for (size_t i = 0; i < ARRAY_SIZE(tinyram_opcodes_stall); ++i) + { + this->pb.val(is_stall_instruction) += this->pb.val(opcode_indicators[tinyram_opcodes_stall[i]]); + } + + /* compute actual result/actual flag */ + compute_computed_result->generate_r1cs_witness(); + compute_computed_flag->generate_r1cs_witness(); + + /* + compute new PC address (in double words, not bytes!): + + PC' = computed_result * is_control_flow_instruction + PC * is_stall_instruction + (PC+1) * (1-is_control_flow_instruction - is_stall_instruction) + PC' - pc_from_cf_or_zero - (1-is_control_flow_instruction - is_stall_instruction) = PC * (1 - is_control_flow_instruction) + */ + this->pb.val(pc_from_cf_or_zero) = this->pb.val(computed_result) * this->pb.val(is_control_flow_instruction); + this->pb.val(packed_outgoing_pc) = + this->pb.val(pc_from_cf_or_zero) + + this->pb.val(packed_incoming_pc) * this->pb.val(is_stall_instruction) + + (this->pb.val(packed_incoming_pc) + FieldT::one()) * (FieldT::one() - this->pb.val(is_control_flow_instruction) - this->pb.val(is_stall_instruction)); + + /* + enforce new flag: + + flag' = computed_flag * is_register_instruction + flag * (1-is_register_instruction) + flag' - flag = (computed_flag - flag) * is_register_instruction + */ + this->pb.val(outgoing_flag) = + this->pb.val(computed_flag) * this->pb.val(is_register_instruction) + + this->pb.val(incoming_flag) * (FieldT::one() - this->pb.val(is_register_instruction)); + + /* + update registers (changed and unchanged) + + next_desval = computed_result * is_register_instruction + packed_incoming_desval * (1-is_register_instruction) + */ + FieldT changed_register_contents = + this->pb.val(computed_result) * this->pb.val(is_register_instruction) + + this->pb.val(packed_incoming_desval) * (FieldT::one() - this->pb.val(is_register_instruction)); + + for (size_t i = 0; i < this->pb.ap.k; ++i) + { + this->pb.val(packed_outgoing_registers[i]) = + (this->pb.val(packed_desidx).as_ulong() == i) ? + changed_register_contents : + this->pb.val(packed_incoming_registers[i]); + } + + /* demux result register (it is important to do witness generation + here after all registers have been set to the correct + values!) */ + demux_packed_outgoing_desval->generate_r1cs_witness(); +} + +#if 0 +template +void test_arithmetic_consistency_enforcer_gadget() +{ + print_time("starting arithmetic_consistency_enforcer test"); + + tinyram_architecture_params ap(16, 16); + tinyram_protoboard pb(ap); + + pb_variable_array opcode_indicators, instruction_results, instruction_flags; + opcode_indicators.allocate(pb, 1ul< desidx(pb, ap.reg_arg_width(), "desidx"); + + pb_variable incoming_pc; + incoming_pc.allocate(pb, "incoming_pc"); + + pb_variable_array packed_incoming_registers; + packed_incoming_registers.allocate(pb, ap.k, "packed_incoming_registers"); + + pb_variable incoming_load_flag; + incoming_load_flag.allocate(pb, "incoming_load_flag"); + + pb_variable outgoing_pc, outgoing_flag; + outgoing_pc.allocate(pb, "outgoing_pc"); + outgoing_flag.allocate(pb, "outgoing_flag"); + + pb_variable_array packed_outgoing_registers; + packed_outgoing_registers.allocate(pb, ap.k, "packed_outgoing_registers"); + + arithmetic_consistency_enforcer_gadget g(pb, opcode_indicators, instruction_results, instruction_flags, + desidx.bits, incoming_pc, packed_incoming_registers, + incoming_load_flag, outgoing_pc, packed_outgoing_registers, outgoing_flag, "g"); + g.generate_r1cs_constraints(); + + for (size_t i = 0; i < 1ul<pb.val(instruction_results[i]) = FieldT(std::rand()); + this->pb.val(instruction_flags[i]) = FieldT(std::rand() % 2); + } + + this->pb.val(incoming_pc) = FieldT(12345); + this->pb.val(incoming_load_flag) = FieldT::zero(); + + for (size_t i = 0; i < ap.k; ++i) + { + this->pb.val(packed_incoming_registers[i]) = FieldT(1000+i); + } + + for (size_t t = 0; t < 1ul<pb.val(opcode_indicators[t]) = FieldT::zero(); + } + + this->pb.val(opcode_indicators[tinyram_opcode_AND]) = FieldT::one(); + + for (size_t i = 0; i < ap.k; ++i) + { + this->pb.val(desidx.packed) = FieldT(i); + desidx.generate_r1cs_witness_from_packed(); + + g.generate_r1cs_witness(); + + assert(this->pb.val(outgoing_pc) == FieldT(12346)); + + for (size_t j = 0; j < ap.k; ++j) + { + assert(this->pb.val(packed_outgoing_registers[j]) == + this->pb.val(i == j ? + instruction_results[tinyram_opcode_AND] : + packed_incoming_registers[j])); + } + + assert(this->pb.val(outgoing_flag) == this->pb.val(instruction_flags[tinyram_opcode_AND])); + assert(pb.is_satisfied()); + } + + printf("arithmetic test successful\n"); + for (size_t t = 0; t < 1ul<pb.val(opcode_indicators[t]) = FieldT::zero(); + } + this->pb.val(opcode_indicators[tinyram_opcode_LOAD]) = FieldT::one(); + this->pb.val(incoming_load_flag) = FieldT::one(); + + g.generate_r1cs_witness(); + + this->pb.val(outgoing_pc) == FieldT(12345); + assert(pb.is_satisfied()); + + this->pb.val(incoming_load_flag) = FieldT::zero(); + printf("test that firstload doesn't increment PC successful\n"); + + for (size_t t = 0; t < 1ul<pb.val(opcode_indicators[t]) = FieldT::zero(); + } + + this->pb.val(opcode_indicators[tinyram_opcode_JMP]) = FieldT::one(); + + for (size_t i = 0; i < ap.k; ++i) + { + this->pb.val(desidx.packed) = FieldT(i); + desidx.generate_r1cs_witness_from_packed(); + + g.generate_r1cs_witness(); + + for (size_t j = 0; j < ap.k; ++j) + { + assert(this->pb.val(packed_outgoing_registers[j]) == this->pb.val(packed_incoming_registers[j])); + } + + assert(pb.is_satisfied()); + } + + printf("non-arithmetic test successful\n"); + + print_time("arithmetic_consistency_enforcer tests successful"); +} + +template +void test_control_flow_consistency_enforcer_gadget() +{ + print_time("starting control_flow_consistency_enforcer test"); + + tinyram_architecture_params ap(16, 16); + tinyram_protoboard pb(ap); + + pb_variable_array opcode_indicators, instruction_results; + opcode_indicators.allocate(pb, 1ul< incoming_pc, incoming_flag; + incoming_pc.allocate(pb, "incoming_pc"); + incoming_flag.allocate(pb, "incoming_flag"); + + pb_variable_array packed_incoming_registers; + packed_incoming_registers.allocate(pb, ap.k, "packed_incoming_registers"); + + pb_variable outgoing_pc, outgoing_flag; + outgoing_pc.allocate(pb, "outgoing_pc"); + outgoing_flag.allocate(pb, "outgoing_flag"); + + pb_variable_array packed_outgoing_registers; + packed_outgoing_registers.allocate(pb, ap.k, "packed_outgoing_registers"); + + control_flow_consistency_enforcer_gadget g(pb, opcode_indicators, instruction_results, + incoming_pc, packed_incoming_registers, incoming_flag, + outgoing_pc, packed_outgoing_registers, outgoing_flag, "g"); + g.generate_r1cs_constraints(); + + for (size_t i = 0; i < 1ul<pb.val(instruction_results[i]) = FieldT(std::rand()); + } + + this->pb.val(incoming_pc) = FieldT(12345); + + for (size_t i = 0; i < ap.k; ++i) + { + this->pb.val(packed_incoming_registers[i]) = FieldT(1000+i); + } + + for (size_t t = 0; t < 1ul<pb.val(opcode_indicators[t]) = FieldT::zero(); + } + this->pb.val(opcode_indicators[tinyram_opcode_JMP]) = FieldT::one(); + + for (int flag = 0; flag <= 1; ++flag) + { + this->pb.val(incoming_flag) = FieldT(flag); + + g.generate_r1cs_witness(); + + assert(this->pb.val(outgoing_pc) == this->pb.val(instruction_results[tinyram_opcode_JMP])); + assert(this->pb.val(outgoing_flag) == this->pb.val(incoming_flag)); + + for (size_t j = 0; j < ap.k; ++j) + { + assert(this->pb.val(packed_outgoing_registers[j]) == this->pb.val(packed_incoming_registers[j])); + } + assert(pb.is_satisfied()); + } + + print_time("control_flow_consistency_enforcer tests successful"); +} + +template +void test_special_consistency_enforcer_gadget() +{ + print_time("starting special_consistency_enforcer_gadget test"); + + tinyram_architecture_params ap(16, 16); + tinyram_protoboard pb(ap); + + pb_variable_array opcode_indicators; + opcode_indicators.allocate(pb, 1ul< incoming_pc, incoming_flag, incoming_load_flag; + incoming_pc.allocate(pb, "incoming_pc"); + incoming_flag.allocate(pb, "incoming_flag"); + incoming_load_flag.allocate(pb, "incoming_load_flag"); + + pb_variable_array packed_incoming_registers; + packed_incoming_registers.allocate(pb, ap.k, "packed_incoming_registers"); + + pb_variable outgoing_pc, outgoing_flag, outgoing_load_flag; + outgoing_pc.allocate(pb, "outgoing_pc"); + outgoing_flag.allocate(pb, "outgoing_flag"); + outgoing_load_flag.allocate(pb, "outgoing_load_flag"); + + pb_variable_array packed_outgoing_registers; + packed_outgoing_registers.allocate(pb, ap.k, "packed_outgoing_registers"); + + special_consistency_enforcer_gadget g(pb, opcode_indicators, + incoming_pc, packed_incoming_registers, incoming_flag, incoming_load_flag, + outgoing_pc, packed_outgoing_registers, outgoing_flag, outgoing_load_flag, "g"); + g.generate_r1cs_constraints(); + + this->pb.val(incoming_pc) = FieldT(12345); + for (size_t i = 0; i < ap.k; ++i) + { + this->pb.val(packed_incoming_registers[i]) = FieldT(1000+i); + } + this->pb.val(incoming_flag) = FieldT::zero(); + this->pb.val(incoming_load_flag) = FieldT::zero(); + + /* test that accept stalls */ + printf("test that ACCEPT stalls\n"); + + for (size_t t = 0; t < 1ul<pb.val(opcode_indicators[t]) = FieldT::zero(); + } + this->pb.val(opcode_indicators[tinyram_opcode_ACCEPT]) = FieldT::one(); + + g.generate_r1cs_witness(); + + assert(this->pb.val(outgoing_flag) == this->pb.val(incoming_flag)); + for (size_t j = 0; j < ap.k; ++j) + { + assert(this->pb.val(packed_outgoing_registers[j]) == this->pb.val(packed_incoming_registers[j])); + } + + assert(this->pb.val(outgoing_pc) == this->pb.val(incoming_pc)); + assert(pb.is_satisfied()); + + printf("test that ACCEPT preserves registers\n"); + this->pb.val(packed_outgoing_registers[0]) = FieldT::zero(); + assert(!pb.is_satisfied()); + + /* test that other special instructions (e.g. STORE) don't and also preserve registers */ + printf("test that others (e.g. STORE) don't stall\n"); + + for (size_t t = 0; t < 1ul<pb.val(opcode_indicators[t]) = FieldT::zero(); + } + this->pb.val(opcode_indicators[tinyram_opcode_STORE]) = FieldT::one(); + + g.generate_r1cs_witness(); + + assert(this->pb.val(outgoing_flag) == this->pb.val(incoming_flag)); + for (size_t j = 0; j < ap.k; ++j) + { + assert(this->pb.val(packed_outgoing_registers[j]) == this->pb.val(packed_incoming_registers[j])); + } + + assert(this->pb.val(outgoing_pc) == this->pb.val(incoming_pc) + FieldT::one()); + assert(pb.is_satisfied()); + + printf("test that STORE preserves registers\n"); + this->pb.val(packed_outgoing_registers[0]) = FieldT::zero(); + assert(!pb.is_satisfied()); + + printf("test that STORE can't have load_flag\n"); + g.generate_r1cs_witness(); + this->pb.val(incoming_load_flag) = FieldT::one(); + + assert(!pb.is_satisfied()); + + /* test that load can modify outgoing register and sets load_flag */ + printf("test that LOAD sets load_flag\n"); + + for (size_t t = 0; t < 1ul<pb.val(opcode_indicators[t]) = FieldT::zero(); + } + this->pb.val(opcode_indicators[tinyram_opcode_LOAD]) = FieldT::one(); + this->pb.val(incoming_load_flag) = FieldT::zero(); + + g.generate_r1cs_witness(); + + assert(this->pb.val(outgoing_load_flag) == FieldT::one()); + assert(pb.is_satisfied()); + + printf("test that LOAD can modify registers\n"); + this->pb.val(packed_outgoing_registers[0]) = FieldT::zero(); + assert(pb.is_satisfied()); + + /* test that postload clears load_flag */ + printf("test that postload clears load_flag\n"); + + for (size_t t = 0; t < 1ul<pb.val(opcode_indicators[t]) = FieldT::zero(); + } + this->pb.val(opcode_indicators[tinyram_opcode_LOAD]) = FieldT::one(); + this->pb.val(incoming_load_flag) = FieldT::one(); + + g.generate_r1cs_witness(); + + assert(this->pb.val(outgoing_load_flag) == FieldT::zero()); + assert(pb.is_satisfied()); + + /* test non-special instructions */ + printf("test non-special instructions\n"); + + for (size_t t = 0; t < 1ul<pb.val(opcode_indicators[t]) = FieldT::zero(); + } + this->pb.val(opcode_indicators[tinyram_opcode_JMP]) = FieldT::one(); + this->pb.val(incoming_load_flag) = FieldT::zero(); + g.generate_r1cs_witness(); + + assert(pb.is_satisfied()); + + printf("test that non-special can't have load_flag\n"); + g.generate_r1cs_witness(); + this->pb.val(incoming_load_flag) = FieldT::one(); + + assert(!pb.is_satisfied()); + + print_time("special_consistency_enforcer_gadget tests successful"); +} +#endif + +} // libsnark + +#endif // CONSISTENCY_ENFORCER_GADGET_TCC_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/cpu_checkers/tinyram/components/instruction_packing_gadget.hpp b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/cpu_checkers/tinyram/components/instruction_packing_gadget.hpp new file mode 100644 index 0000000..8f247d1 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/cpu_checkers/tinyram/components/instruction_packing_gadget.hpp @@ -0,0 +1,58 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for the TinyRAM instruction packing gadget. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef INSTRUCTION_PACKING_GADGET_HPP_ +#define INSTRUCTION_PACKING_GADGET_HPP_ + +namespace libsnark { + +template +class tinyram_instruction_packing_gadget : public tinyram_gadget { +private: + pb_variable_array all_bits; + + std::shared_ptr > pack_instruction; +public: + pb_variable_array opcode; + pb_variable arg2_is_imm; + pb_variable_array desidx; + pb_variable_array arg1idx; + pb_variable_array arg2idx; + pb_variable packed_instruction; + + pb_variable_array dummy; + + tinyram_instruction_packing_gadget(tinyram_protoboard &pb, + const pb_variable_array &opcode, + const pb_variable &arg2_is_imm, + const pb_variable_array &desidx, + const pb_variable_array &arg1idx, + const pb_variable_array &arg2idx, + const pb_variable &packed_instruction, + const std::string &annotation_prefix=""); + + void generate_r1cs_constraints(const bool enforce_bitness); + void generate_r1cs_witness_from_packed(); + void generate_r1cs_witness_from_bits(); +}; + +template +FieldT pack_instruction(const tinyram_architecture_params &ap, + const tinyram_instruction &instr); + +template +void test_instruction_packing(); + +} // libsnark + +#include "gadgetlib1/gadgets/cpu_checkers/tinyram/components/instruction_packing_gadget.tcc" + +#endif // INSTRUCTION_PACKING_GADGET_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/cpu_checkers/tinyram/components/instruction_packing_gadget.tcc b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/cpu_checkers/tinyram/components/instruction_packing_gadget.tcc new file mode 100644 index 0000000..5691dd8 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/cpu_checkers/tinyram/components/instruction_packing_gadget.tcc @@ -0,0 +1,195 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for the TinyRAM instruction packing gadget. + + See instruction_packing_gadget.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef INSTRUCTION_PACKING_GADGET_TCC_ +#define INSTRUCTION_PACKING_GADGET_TCC_ + +namespace libsnark { + +template +tinyram_instruction_packing_gadget::tinyram_instruction_packing_gadget(tinyram_protoboard &pb, + const pb_variable_array &opcode, + const pb_variable &arg2_is_imm, + const pb_variable_array &desidx, + const pb_variable_array &arg1idx, + const pb_variable_array &arg2idx, + const pb_variable &packed_instruction, + const std::string &annotation_prefix) : + tinyram_gadget(pb, annotation_prefix), + opcode(opcode), + arg2_is_imm(arg2_is_imm), + desidx(desidx), + arg1idx(arg1idx), + arg2idx(arg2idx), + packed_instruction(packed_instruction) +{ + all_bits.reserve(2*pb.ap.w); + + all_bits.insert(all_bits.begin(), opcode.begin(), opcode.end()); + all_bits.insert(all_bits.begin(), arg2_is_imm); + all_bits.insert(all_bits.begin(), desidx.begin(), desidx.end()); + all_bits.insert(all_bits.begin(), arg1idx.begin(), arg1idx.end()); + dummy.allocate(pb, pb.ap.w-all_bits.size(), FMT(this->annotation_prefix, " dummy")); + all_bits.insert(all_bits.begin(), dummy.begin(), dummy.end()); + all_bits.insert(all_bits.begin(), arg2idx.begin(), arg2idx.end()); + + assert(all_bits.size() == 2*pb.ap.w); + + pack_instruction.reset( + new packing_gadget(pb, all_bits, packed_instruction, FMT(this->annotation_prefix, " pack_instruction"))); +} + + +template +void tinyram_instruction_packing_gadget::generate_r1cs_constraints(const bool enforce_bitness) +{ + pack_instruction->generate_r1cs_constraints(enforce_bitness); +} + +template +void tinyram_instruction_packing_gadget::generate_r1cs_witness_from_packed() +{ + pack_instruction->generate_r1cs_witness_from_packed(); +} + +template +void tinyram_instruction_packing_gadget::generate_r1cs_witness_from_bits() +{ + pack_instruction->generate_r1cs_witness_from_bits(); +} + +template +FieldT pack_instruction(const tinyram_architecture_params &ap, + const tinyram_instruction &instr) +{ + tinyram_program P; P.instructions = generate_tinyram_prelude(ap); + tinyram_protoboard pb(ap, P.size(), 0, 10); + + pb_variable_array v_opcode; + pb_variable v_arg2_is_imm; + pb_variable_array v_desidx; + pb_variable_array v_arg1idx; + pb_variable_array v_arg2idx; + + v_opcode.allocate(pb, ap.s, "opcode"); + v_arg2_is_imm.allocate(pb, "arg2_is_imm"); + v_desidx.allocate(pb, ap.reg_arg_width(), "desidx"); + v_arg1idx.allocate(pb, ap.reg_arg_width(), "arg1idx"); + v_arg2idx.allocate(pb, ap.reg_arg_or_imm_width(), "arg2idx"); + + v_opcode.fill_with_bits_of_ulong(pb, instr.opcode); + pb.val(v_arg2_is_imm) = instr.arg2_is_imm ? FieldT::one() : FieldT::zero(); + v_desidx.fill_with_bits_of_ulong(pb, instr.desidx); + v_arg1idx.fill_with_bits_of_ulong(pb, instr.arg1idx); + v_arg2idx.fill_with_bits_of_ulong(pb, instr.arg2idx_or_imm); + + pb_variable packed; + packed.allocate(pb, "packed"); + + tinyram_instruction_packing_gadget g(pb, v_opcode, v_arg2_is_imm, v_desidx, v_arg1idx, v_arg2idx, packed, "g"); + g.generate_r1cs_constraints(true); + g.generate_r1cs_witness_from_bits(); + + return pb.val(packed); +} + +template +void test_instruction_packing() +{ + print_time("starting instruction packing test"); + + tinyram_architecture_params ap(16, 16); + tinyram_program P; P.instructions = generate_tinyram_prelude(ap); + tinyram_protoboard pb(ap, P.size(), 0, 10); + + pb_variable_array opcode[2]; + pb_variable arg2_is_imm[2]; + pb_variable_array desidx[2]; + pb_variable_array arg1idx[2]; + pb_variable_array arg2idx[2]; + + for (size_t i = 0; i < 2; ++i) + { + opcode[i].allocate(pb, ap.s, FMT("", "opcode_%zu", i)); + arg2_is_imm[i].allocate(pb, FMT("", "arg2_is_imm_%zu", i)); + desidx[i].allocate(pb, ap.reg_arg_width(), FMT("", "desidx_%zu", i)); + arg1idx[i].allocate(pb, ap.reg_arg_width(), FMT("", "arg1idx_%zu", i)); + arg2idx[i].allocate(pb, ap.reg_arg_or_imm_width(), FMT("", "arg2idx_%zu", i)); + } + + pb_variable packed_instr; + packed_instr.allocate(pb, "packed_instr"); + + instruction_packing_gadget pack(pb, opcode[0], arg2_is_imm[0], desidx[0], arg1idx[0], arg2idx[0], packed_instr, "pack"); + instruction_packing_gadget unpack(pb, opcode[1], arg2_is_imm[1], desidx[1], arg1idx[1], arg2idx[1], packed_instr, "unpack"); + + pack.generate_r1cs_constraints(true); + unpack.generate_r1cs_constraints(true); + + for (size_t k = 0; k < 100; ++k) + { + tinyram_opcode oc = static_cast(std::rand() % (1u << ap.s)); + bool imm = std::rand() % 2; + size_t des = rand() % (1u << ap.reg_arg_width()); + size_t arg1 = rand() % (1u << ap.reg_arg_width()); + size_t arg2 = rand() % (1u << ap.reg_arg_or_imm_width()); + + for (size_t i = 0; i < ap.s; ++i) + { + pb.val(opcode[0][i]) = (oc & (1ul<(ap, tinyram_instruction(oc, imm, des, arg1, arg2))); + assert(pb.is_satisfied()); + } + + print_time("instruction packing tests successful"); +} + +} // libsnark + +#endif // INSTRUCTION_PACKING_GADGET_TCC_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/cpu_checkers/tinyram/components/memory_masking_gadget.hpp b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/cpu_checkers/tinyram/components/memory_masking_gadget.hpp new file mode 100644 index 0000000..5096aa3 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/cpu_checkers/tinyram/components/memory_masking_gadget.hpp @@ -0,0 +1,94 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for the TinyRAM memory masking gadget. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef MEMORY_MASKING_GADGET_HPP_ +#define MEMORY_MASKING_GADGET_HPP_ + +namespace libsnark { + +/** + * The memory masking gadget checks if a specified part of a double + * word is correctly modified. In TinyRAM CPU checker we use this to + * implement byte addressing and word addressing for the memory that + * consists of double words. + * + * More precisely, memory masking gadgets takes the following + * arguments: + * + * dw_contents_prev, dw_contents_next -- the contents of the memory + * + * double word before and after the access + * + * access_is_word -- a boolean indicating if access is word + * + * access_is_byte -- a boolean indicating if access is byte + * + * subaddress -- an integer specifying which byte (if access_is_byte=1) + * or word (if access_is_byte=1) this access is operating on + * + * subcontents -- contents of the byte, resp., word to be operated on + * + * Memory masking gadget enforces that dw_contents_prev is equal to + * dw_contents_next everywhere, except subaddres-th byte (if + * access_is_byte = 1), or MSB(subaddress)-th word (if access_is_word = + * 1). The corresponding byte, resp., word in dw_contents_next is + * required to equal subcontents. + * + * Note that indexing MSB(subaddress)-th word is the same as indexing + * the word specified by subaddress expressed in bytes and aligned to + * the word boundary by rounding the subaddress down. + * + * Requirements: The caller is required to perform bounds checks on + * subcontents. The caller is also required to ensure that exactly one + * of access_is_word and access_is_byte is set to 1. + */ +template +class memory_masking_gadget : public tinyram_standard_gadget { +private: + pb_linear_combination shift; + pb_variable is_word0; + pb_variable is_word1; + pb_variable_array is_subaddress; + pb_variable_array is_byte; + + pb_linear_combination masked_out_word0; + pb_linear_combination masked_out_word1; + pb_linear_combination_array masked_out_bytes; + + std::shared_ptr > get_masked_out_dw_contents_prev; + + pb_variable masked_out_dw_contents_prev; + pb_variable expected_dw_contents_next; +public: + doubleword_variable_gadget dw_contents_prev; + dual_variable_gadget subaddress; + pb_linear_combination subcontents; + pb_linear_combination access_is_word; + pb_linear_combination access_is_byte; + doubleword_variable_gadget dw_contents_next; + + memory_masking_gadget(tinyram_protoboard &pb, + const doubleword_variable_gadget &dw_contents_prev, + const dual_variable_gadget &subaddress, + const pb_linear_combination &subcontents, + const pb_linear_combination &access_is_word, + const pb_linear_combination &access_is_byte, + const doubleword_variable_gadget &dw_contents_next, + const std::string& annotation_prefix=""); + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +} // libsnark + +#include "gadgetlib1/gadgets/cpu_checkers/tinyram/components/memory_masking_gadget.tcc" + +#endif // MEMORY_MASKING_GADGET_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/cpu_checkers/tinyram/components/memory_masking_gadget.tcc b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/cpu_checkers/tinyram/components/memory_masking_gadget.tcc new file mode 100644 index 0000000..99e2538 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/cpu_checkers/tinyram/components/memory_masking_gadget.tcc @@ -0,0 +1,171 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for the TinyRAM memory masking gadget. + + See memory_masking_gadget.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef MEMORY_MASKING_GADGET_TCC_ +#define MEMORY_MASKING_GADGET_TCC_ + +namespace libsnark { + +template +memory_masking_gadget::memory_masking_gadget(tinyram_protoboard &pb, + const doubleword_variable_gadget &dw_contents_prev, + const dual_variable_gadget &subaddress, + const pb_linear_combination &subcontents, + const pb_linear_combination &access_is_word, + const pb_linear_combination &access_is_byte, + const doubleword_variable_gadget &dw_contents_next, + const std::string& annotation_prefix) : + tinyram_standard_gadget(pb, annotation_prefix), + dw_contents_prev(dw_contents_prev), + subaddress(subaddress), + subcontents(subcontents), + access_is_word(access_is_word), + access_is_byte(access_is_byte), + dw_contents_next(dw_contents_next) +{ + /* + Indicator variables for access being to word_0, word_1, and + byte_0, byte_1, ... + + We use little-endian indexing here (least significant + bit/byte/word has the smallest address). + */ + is_word0.allocate(pb, FMT(this->annotation_prefix, " is_word0")); + is_word1.allocate(pb, FMT(this->annotation_prefix, " is_word1")); + is_subaddress.allocate(pb, 2 * pb.ap.bytes_in_word(), FMT(this->annotation_prefix, " is_sub_address")); + is_byte.allocate(pb, 2 * pb.ap.bytes_in_word(), FMT(this->annotation_prefix, " is_byte")); + + /* + Get value of the dw_contents_prev for which the specified entity + is masked out to be zero. E.g. the value of masked_out_bytes[3] + will be the same as the value of dw_contents_prev, when 3rd + (0-indexed) byte is set to all zeros. + */ + masked_out_word0.assign(pb, (FieldT(2)^pb.ap.w) * pb_packing_sum( + pb_variable_array(dw_contents_prev.bits.begin() + pb.ap.w, + dw_contents_prev.bits.begin() + 2 * pb.ap.w))); + masked_out_word1.assign(pb, pb_packing_sum( + pb_variable_array(dw_contents_prev.bits.begin(), + dw_contents_prev.bits.begin() + pb.ap.w))); + masked_out_bytes.resize(2 * pb.ap.bytes_in_word()); + + for (size_t i = 0; i < 2 * pb.ap.bytes_in_word(); ++i) + { + /* just subtract out the byte to be masked */ + masked_out_bytes[i].assign(pb, (dw_contents_prev.packed - + (FieldT(2)^(8*i)) * pb_packing_sum( + pb_variable_array(dw_contents_prev.bits.begin() + 8*i, + dw_contents_prev.bits.begin() + 8*(i+1))))); + } + + /* + Define masked_out_dw_contents_prev to be the correct masked out + contents for the current access type. + */ + + pb_linear_combination_array masked_out_indicators; + masked_out_indicators.emplace_back(is_word0); + masked_out_indicators.emplace_back(is_word1); + masked_out_indicators.insert(masked_out_indicators.end(), is_byte.begin(), is_byte.end()); + + pb_linear_combination_array masked_out_results; + masked_out_results.emplace_back(masked_out_word0); + masked_out_results.emplace_back(masked_out_word1); + masked_out_results.insert(masked_out_results.end(), masked_out_bytes.begin(), masked_out_bytes.end()); + + masked_out_dw_contents_prev.allocate(pb, FMT(this->annotation_prefix, " masked_out_dw_contents_prev")); + get_masked_out_dw_contents_prev.reset(new inner_product_gadget(pb, masked_out_indicators, masked_out_results, masked_out_dw_contents_prev, + FMT(this->annotation_prefix, " get_masked_out_dw_contents_prev"))); + + /* + Define shift so that masked_out_dw_contents_prev + shift * subcontents = dw_contents_next + */ + linear_combination shift_lc = is_word0 * 1 + is_word1 * (FieldT(2)^this->pb.ap.w); + for (size_t i = 0; i < 2 * this->pb.ap.bytes_in_word(); ++i) + { + shift_lc = shift_lc + is_byte[i] * (FieldT(2)^(8*i)); + } + shift.assign(pb, shift_lc); +} + +template +void memory_masking_gadget::generate_r1cs_constraints() +{ + /* get indicator variables for is_subaddress[i] by adding constraints + is_subaddress[i] * (subaddress - i) = 0 and \sum_i is_subaddress[i] = 1 */ + for (size_t i = 0; i < 2 * this->pb.ap.bytes_in_word(); ++i) + { + this->pb.add_r1cs_constraint(r1cs_constraint(is_subaddress[i], subaddress.packed - i, 0), + FMT(this->annotation_prefix, " is_subaddress_%zu", i)); + } + this->pb.add_r1cs_constraint(r1cs_constraint(1, pb_sum(is_subaddress), 1), FMT(this->annotation_prefix, " is_subaddress")); + + /* get indicator variables is_byte_X */ + for (size_t i = 0; i < 2 * this->pb.ap.bytes_in_word(); ++i) + { + this->pb.add_r1cs_constraint(r1cs_constraint(access_is_byte, is_subaddress[i], is_byte[i]), + FMT(this->annotation_prefix, " is_byte_%zu", i)); + } + + /* get indicator variables is_word_0/is_word_1 */ + this->pb.add_r1cs_constraint(r1cs_constraint(access_is_word, 1 - subaddress.bits[this->pb.ap.subaddr_len()-1], is_word0), + FMT(this->annotation_prefix, " is_word_0")); + this->pb.add_r1cs_constraint(r1cs_constraint(access_is_word, subaddress.bits[this->pb.ap.subaddr_len()-1], is_word1), + FMT(this->annotation_prefix, " is_word_1")); + + /* compute masked_out_dw_contents_prev */ + get_masked_out_dw_contents_prev->generate_r1cs_constraints(); + + /* + masked_out_dw_contents_prev + shift * subcontents = dw_contents_next + */ + this->pb.add_r1cs_constraint(r1cs_constraint(shift, subcontents, dw_contents_next.packed - masked_out_dw_contents_prev), + FMT(this->annotation_prefix, " mask_difference")); +} + +template +void memory_masking_gadget::generate_r1cs_witness() +{ + /* get indicator variables is_subaddress */ + for (size_t i = 0; i < 2 * this->pb.ap.bytes_in_word(); ++i) + { + this->pb.val(is_subaddress[i]) = (this->pb.val(subaddress.packed) == FieldT(i)) ? FieldT::one() : FieldT::zero(); + } + + /* get indicator variables is_byte_X */ + for (size_t i = 0; i < 2 * this->pb.ap.bytes_in_word(); ++i) + { + this->pb.val(is_byte[i]) = this->pb.val(is_subaddress[i]) * this->pb.lc_val(access_is_byte); + } + + /* get indicator variables is_word_0/is_word_1 */ + this->pb.val(is_word0) = (FieldT::one() - this->pb.val(subaddress.bits[this->pb.ap.subaddr_len()-1])) * this->pb.lc_val(access_is_word); + this->pb.val(is_word1) = this->pb.val(subaddress.bits[this->pb.ap.subaddr_len()-1]) * this->pb.lc_val(access_is_word); + + /* calculate shift and masked out words/bytes */ + shift.evaluate(this->pb); + masked_out_word0.evaluate(this->pb); + masked_out_word1.evaluate(this->pb); + masked_out_bytes.evaluate(this->pb); + + /* get masked_out dw/word0/word1/bytes */ + get_masked_out_dw_contents_prev->generate_r1cs_witness(); + + /* compute dw_contents_next */ + this->pb.val(dw_contents_next.packed) = this->pb.val(masked_out_dw_contents_prev) + this->pb.lc_val(shift) * this->pb.lc_val(subcontents); + dw_contents_next.generate_r1cs_witness_from_packed(); +} + +} // libsnark + +#endif // MEMORY_MASKING_GADGET_TCC_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/cpu_checkers/tinyram/components/tinyram_protoboard.hpp b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/cpu_checkers/tinyram/components/tinyram_protoboard.hpp new file mode 100644 index 0000000..c84ea7c --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/cpu_checkers/tinyram/components/tinyram_protoboard.hpp @@ -0,0 +1,52 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for a protoboard for TinyRAM. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef TINYRAM_PROTOBOARD_HPP_ +#define TINYRAM_PROTOBOARD_HPP_ + +#include "relations/ram_computations/rams/ram_params.hpp" +#include "relations/ram_computations/rams/tinyram/tinyram_aux.hpp" +#include "gadgetlib1/protoboard.hpp" +#include "gadgetlib1/gadgets/basic_gadgets.hpp" + +namespace libsnark { + +template +class tinyram_protoboard : public protoboard { +public: + const tinyram_architecture_params ap; + + tinyram_protoboard(const tinyram_architecture_params &ap); +}; + +template +class tinyram_gadget : public gadget { +protected: + tinyram_protoboard &pb; +public: + tinyram_gadget(tinyram_protoboard &pb, const std::string &annotation_prefix=""); +}; + +// standard gadgets provide two methods: generate_r1cs_constraints and generate_r1cs_witness +template +class tinyram_standard_gadget : public tinyram_gadget { +public: + tinyram_standard_gadget(tinyram_protoboard &pb, const std::string &annotation_prefix=""); + + virtual void generate_r1cs_constraints() = 0; + virtual void generate_r1cs_witness() = 0; +}; + +} // libsnark + +#include "gadgetlib1/gadgets/cpu_checkers/tinyram/components/tinyram_protoboard.tcc" + +#endif // TINYRAM_PROTOBOARD_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/cpu_checkers/tinyram/components/tinyram_protoboard.tcc b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/cpu_checkers/tinyram/components/tinyram_protoboard.tcc new file mode 100644 index 0000000..c70b9db --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/cpu_checkers/tinyram/components/tinyram_protoboard.tcc @@ -0,0 +1,39 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for a protoboard for TinyRAM. + + See tinyram_protoboard.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef TINYRAM_PROTOBOARD_TCC_ +#define TINYRAM_PROTOBOARD_TCC_ + +namespace libsnark { + +template +tinyram_protoboard::tinyram_protoboard(const tinyram_architecture_params &ap) : + ap(ap) +{ +} + +template +tinyram_gadget::tinyram_gadget(tinyram_protoboard &pb, const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), pb(pb) +{ +} + +template +tinyram_standard_gadget::tinyram_standard_gadget(tinyram_protoboard &pb, const std::string &annotation_prefix) : + tinyram_gadget(pb, annotation_prefix) +{ +} + +} // libsnark + +#endif // TINYRAM_PROTOBOARD_TCC_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/cpu_checkers/tinyram/components/word_variable_gadget.hpp b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/cpu_checkers/tinyram/components/word_variable_gadget.hpp new file mode 100644 index 0000000..24c462b --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/cpu_checkers/tinyram/components/word_variable_gadget.hpp @@ -0,0 +1,49 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for (single and double) word gadgets. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef WORD_VARIABLE_GADGET_HPP_ +#define WORD_VARIABLE_GADGET_HPP_ + +#include "gadgetlib1/gadgets/cpu_checkers/tinyram/components/tinyram_protoboard.hpp" + +namespace libsnark { + +/** + * Holds both binary and field representaton of a word. + */ +template +class word_variable_gadget : public dual_variable_gadget { +public: + word_variable_gadget(tinyram_protoboard &pb, const std::string &annotation_prefix="") : + dual_variable_gadget(pb, pb.ap.w, annotation_prefix) {} + word_variable_gadget(tinyram_protoboard &pb, const pb_variable_array &bits, const std::string &annotation_prefix="") : + dual_variable_gadget(pb, bits, annotation_prefix) {} + word_variable_gadget(tinyram_protoboard &pb, const pb_variable &packed, const std::string &annotation_prefix="") : + dual_variable_gadget(pb, packed, pb.ap.w, annotation_prefix) {} +}; + +/** + * Holds both binary and field representaton of a double word. + */ +template +class doubleword_variable_gadget : public dual_variable_gadget { +public: + doubleword_variable_gadget(tinyram_protoboard &pb, const std::string &annotation_prefix="") : + dual_variable_gadget(pb, 2*pb.ap.w, annotation_prefix) {} + doubleword_variable_gadget(tinyram_protoboard &pb, const pb_variable_array &bits, const std::string &annotation_prefix="") : + dual_variable_gadget(pb, bits, annotation_prefix) {} + doubleword_variable_gadget(tinyram_protoboard &pb, const pb_variable &packed, const std::string &annotation_prefix="") : + dual_variable_gadget(pb, packed, 2*pb.ap.w, annotation_prefix) {} +}; + +} // libsnark + +#endif // WORD_VARIABLE_GADGET_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/cpu_checkers/tinyram/tinyram_cpu_checker.hpp b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/cpu_checkers/tinyram/tinyram_cpu_checker.hpp new file mode 100644 index 0000000..3168ec3 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/cpu_checkers/tinyram/tinyram_cpu_checker.hpp @@ -0,0 +1,101 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for the TinyRAM CPU checker gadget. + + The gadget checks the correct operation for the CPU of the TinyRAM architecture. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef TINYRAM_CPU_CHECKER_HPP_ +#define TINYRAM_CPU_CHECKER_HPP_ + +#include "gadgetlib1/gadgets/cpu_checkers/tinyram/components/tinyram_protoboard.hpp" +#include "gadgetlib1/gadgets/cpu_checkers/tinyram/components/word_variable_gadget.hpp" +#include "gadgetlib1/gadgets/cpu_checkers/tinyram/components/alu_gadget.hpp" +#include "gadgetlib1/gadgets/cpu_checkers/tinyram/components/argument_decoder_gadget.hpp" +#include "gadgetlib1/gadgets/cpu_checkers/tinyram/components/consistency_enforcer_gadget.hpp" +#include "gadgetlib1/gadgets/cpu_checkers/tinyram/components/memory_masking_gadget.hpp" + +namespace libsnark { + +template +class tinyram_cpu_checker : public tinyram_standard_gadget { +private: + pb_variable_array opcode; + pb_variable arg2_is_imm; + pb_variable_array desidx; + pb_variable_array arg1idx; + pb_variable_array arg2idx; + + std::vector > prev_registers; + std::vector > next_registers; + pb_variable prev_flag; + pb_variable next_flag; + pb_variable prev_tape1_exhausted; + pb_variable next_tape1_exhausted; + + std::shared_ptr > prev_pc_addr_as_word_variable; + std::shared_ptr > desval; + std::shared_ptr > arg1val; + std::shared_ptr > arg2val; + + std::shared_ptr > decode_arguments; + pb_variable_array opcode_indicators; + std::shared_ptr > ALU; + + std::shared_ptr > ls_prev_val_as_doubleword_variable; + std::shared_ptr > ls_next_val_as_doubleword_variable; + std::shared_ptr > memory_subaddress; + pb_variable memory_subcontents; + pb_linear_combination memory_access_is_word; + pb_linear_combination memory_access_is_byte; + std::shared_ptr > check_memory; + + std::shared_ptr > next_pc_addr_as_word_variable; + std::shared_ptr > consistency_enforcer; + + pb_variable_array instruction_results; + pb_variable_array instruction_flags; + + pb_variable read_not1; +public: + pb_variable_array prev_pc_addr; + pb_variable_array prev_pc_val; + pb_variable_array prev_state; + pb_variable_array ls_addr; + pb_variable_array ls_prev_val; + pb_variable_array ls_next_val; + pb_variable_array next_state; + pb_variable_array next_pc_addr; + pb_variable next_has_accepted; + + tinyram_cpu_checker(tinyram_protoboard &pb, + pb_variable_array &prev_pc_addr, + pb_variable_array &prev_pc_val, + pb_variable_array &prev_state, + pb_variable_array &ls_addr, + pb_variable_array &ls_prev_val, + pb_variable_array &ls_next_val, + pb_variable_array &next_state, + pb_variable_array &next_pc_addr, + pb_variable &next_has_accepted, + const std::string &annotation_prefix); + + void generate_r1cs_constraints(); + void generate_r1cs_witness() { assert(0); } + void generate_r1cs_witness_address(); + void generate_r1cs_witness_other(tinyram_input_tape_iterator &aux_it, + const tinyram_input_tape_iterator &aux_end); + void dump() const; +}; + +} // libsnark + +#include "gadgetlib1/gadgets/cpu_checkers/tinyram/tinyram_cpu_checker.tcc" + +#endif // TINYRAM_CPU_CHECKER_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/cpu_checkers/tinyram/tinyram_cpu_checker.tcc b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/cpu_checkers/tinyram/tinyram_cpu_checker.tcc new file mode 100644 index 0000000..446ec8b --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/cpu_checkers/tinyram/tinyram_cpu_checker.tcc @@ -0,0 +1,397 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for the TinyRAM CPU checker gadget. + + See tinyram_cpu_checker.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef TINYRAM_CPU_CHECKER_TCC_ +#define TINYRAM_CPU_CHECKER_TCC_ + +#include "algebra/fields/field_utils.hpp" + +namespace libsnark { + +template +tinyram_cpu_checker::tinyram_cpu_checker(tinyram_protoboard &pb, + pb_variable_array &prev_pc_addr, + pb_variable_array &prev_pc_val, + pb_variable_array &prev_state, + pb_variable_array &ls_addr, + pb_variable_array &ls_prev_val, + pb_variable_array &ls_next_val, + pb_variable_array &next_state, + pb_variable_array &next_pc_addr, + pb_variable &next_has_accepted, + const std::string &annotation_prefix) : +tinyram_standard_gadget(pb, annotation_prefix), prev_pc_addr(prev_pc_addr), prev_pc_val(prev_pc_val), + prev_state(prev_state), ls_addr(ls_addr), ls_prev_val(ls_prev_val), ls_next_val(ls_next_val), + next_state(next_state), next_pc_addr(next_pc_addr), next_has_accepted(next_has_accepted) +{ + /* parse previous PC value as an instruction (note that we start + parsing from LSB of the instruction doubleword and go to the + MSB) */ + auto pc_val_it = prev_pc_val.begin(); + + arg2idx = pb_variable_array(pc_val_it, pc_val_it + pb.ap.reg_arg_or_imm_width()); std::advance(pc_val_it, pb.ap.reg_arg_or_imm_width()); + std::advance(pc_val_it, pb.ap.instruction_padding_width()); + arg1idx = pb_variable_array(pc_val_it, pc_val_it + pb.ap.reg_arg_width()); std::advance(pc_val_it, pb.ap.reg_arg_width()); + desidx = pb_variable_array(pc_val_it, pc_val_it + pb.ap.reg_arg_width()); std::advance(pc_val_it, pb.ap.reg_arg_width()); + arg2_is_imm = *pc_val_it; std::advance(pc_val_it, 1); + opcode = pb_variable_array(pc_val_it, pc_val_it + pb.ap.opcode_width()); std::advance(pc_val_it, pb.ap.opcode_width()); + + assert(pc_val_it == prev_pc_val.end()); + + /* parse state as registers + flags */ + pb_variable_array packed_prev_registers, packed_next_registers; + for (size_t i = 0; i < pb.ap.k; ++i) + { + prev_registers.emplace_back(word_variable_gadget(pb, pb_variable_array(prev_state.begin() + i * pb.ap.w, prev_state.begin() + (i + 1) * pb.ap.w), FMT(annotation_prefix, " prev_registers_%zu", i))); + next_registers.emplace_back(word_variable_gadget(pb, pb_variable_array(next_state.begin() + i * pb.ap.w, next_state.begin() + (i + 1) * pb.ap.w), FMT(annotation_prefix, " next_registers_%zu", i))); + + packed_prev_registers.emplace_back(prev_registers[i].packed); + packed_next_registers.emplace_back(next_registers[i].packed); + } + prev_flag = *(++prev_state.rbegin()); + next_flag = *(++next_state.rbegin()); + prev_tape1_exhausted = *(prev_state.rbegin()); + next_tape1_exhausted = *(next_state.rbegin()); + + /* decode arguments */ + prev_pc_addr_as_word_variable.reset(new word_variable_gadget(pb, prev_pc_addr, FMT(annotation_prefix, " prev_pc_addr_as_word_variable"))); + desval.reset(new word_variable_gadget(pb, FMT(annotation_prefix, " desval"))); + arg1val.reset(new word_variable_gadget(pb, FMT(annotation_prefix, " arg1val"))); + arg2val.reset(new word_variable_gadget(pb, FMT(annotation_prefix, " arg2val"))); + + decode_arguments.reset(new argument_decoder_gadget(pb, arg2_is_imm, desidx, arg1idx, arg2idx, packed_prev_registers, + desval->packed, arg1val->packed, arg2val->packed, + FMT(annotation_prefix, " decode_arguments"))); + + /* create indicator variables for opcodes */ + opcode_indicators.allocate(pb, 1ul<(pb, opcode_indicators, *prev_pc_addr_as_word_variable, *desval, *arg1val, *arg2val, prev_flag, instruction_results, instruction_flags, + FMT(annotation_prefix, " ALU"))); + + /* check correctness of memory operations */ + ls_prev_val_as_doubleword_variable.reset(new doubleword_variable_gadget(pb, ls_prev_val, FMT(annotation_prefix, " ls_prev_val_as_doubleword_variable"))) +; + ls_next_val_as_doubleword_variable.reset(new doubleword_variable_gadget(pb, ls_next_val, FMT(annotation_prefix, " ls_next_val_as_doubleword_variable"))); + memory_subaddress.reset(new dual_variable_gadget(pb, pb_variable_array(arg2val->bits.begin(), arg2val->bits.begin() + pb.ap.subaddr_len()), + FMT(annotation_prefix, " memory_subaddress"))); + + memory_subcontents.allocate(pb, FMT(annotation_prefix, " memory_subcontents")); + memory_access_is_word.assign(pb, 1 - (opcode_indicators[tinyram_opcode_LOADB] + opcode_indicators[tinyram_opcode_STOREB])); + memory_access_is_byte.assign(pb, opcode_indicators[tinyram_opcode_LOADB] + opcode_indicators[tinyram_opcode_STOREB]); + + check_memory.reset(new memory_masking_gadget(pb, + *ls_prev_val_as_doubleword_variable, + *memory_subaddress, + memory_subcontents, + memory_access_is_word, + memory_access_is_byte, + *ls_next_val_as_doubleword_variable, + FMT(annotation_prefix, " check_memory"))); + + /* handle reads */ + read_not1.allocate(pb, FMT(annotation_prefix, " read_not1")); + + /* check consistency of the states according to the ALU results */ + next_pc_addr_as_word_variable.reset(new word_variable_gadget(pb, next_pc_addr, FMT(annotation_prefix, " next_pc_addr_as_word_variable"))); + + consistency_enforcer.reset(new consistency_enforcer_gadget(pb, opcode_indicators, instruction_results, instruction_flags, + desidx, prev_pc_addr_as_word_variable->packed, + packed_prev_registers, + desval->packed, + prev_flag, + next_pc_addr_as_word_variable->packed, + packed_next_registers, + next_flag, + FMT(annotation_prefix, " consistency_enforcer"))); +} + +template +void tinyram_cpu_checker::generate_r1cs_constraints() +{ + decode_arguments->generate_r1cs_constraints(); + + /* generate indicator variables for opcode */ + for (size_t i = 0; i < 1ul<pb.ap.opcode_width(); ++i) + { + this->pb.add_r1cs_constraint(r1cs_constraint(opcode_indicators[i], pb_packing_sum(opcode) - i, 0), + FMT(this->annotation_prefix, " opcode_indicators_%zu", i)); + } + this->pb.add_r1cs_constraint(r1cs_constraint(1, pb_sum(opcode_indicators), 1), + FMT(this->annotation_prefix, " opcode_indicators_sum_to_1")); + + /* consistency checks for repacked variables */ + for (size_t i = 0; i < this->pb.ap.k; ++i) + { + prev_registers[i].generate_r1cs_constraints(true); + next_registers[i].generate_r1cs_constraints(true); + } + prev_pc_addr_as_word_variable->generate_r1cs_constraints(true); + next_pc_addr_as_word_variable->generate_r1cs_constraints(true); + ls_prev_val_as_doubleword_variable->generate_r1cs_constraints(true); + ls_next_val_as_doubleword_variable->generate_r1cs_constraints(true); + + /* main consistency checks */ + decode_arguments->generate_r1cs_constraints(); + ALU->generate_r1cs_constraints(); + consistency_enforcer->generate_r1cs_constraints(); + + /* check correct access to memory */ + ls_prev_val_as_doubleword_variable->generate_r1cs_constraints(false); + ls_next_val_as_doubleword_variable->generate_r1cs_constraints(false); + memory_subaddress->generate_r1cs_constraints(false); + check_memory->generate_r1cs_constraints(); + + this->pb.add_r1cs_constraint(r1cs_constraint(1, + pb_packing_sum( + pb_variable_array(arg2val->bits.begin() + this->pb.ap.subaddr_len(), + arg2val->bits.end())), + pb_packing_sum(ls_addr)), + FMT(this->annotation_prefix, " ls_addr_is_arg2val_minus_subaddress")); + + /* We require that if opcode is one of load.{b,w}, then + subcontents is appropriately stored in instruction_results. If + opcode is store.b we only take the necessary portion of arg1val + (i.e. last byte), and take entire arg1val for store.w. + + Note that ls_addr is *always* going to be arg2val. If the + instruction is a non-memory instruction, we will treat it as a + load from that memory location. */ + this->pb.add_r1cs_constraint(r1cs_constraint(opcode_indicators[tinyram_opcode_LOADB], + memory_subcontents - instruction_results[tinyram_opcode_LOADB], + 0), + FMT(this->annotation_prefix, " handle_loadb")); + this->pb.add_r1cs_constraint(r1cs_constraint(opcode_indicators[tinyram_opcode_LOADW], + memory_subcontents - instruction_results[tinyram_opcode_LOADW], + 0), + FMT(this->annotation_prefix, " handle_loadw")); + this->pb.add_r1cs_constraint(r1cs_constraint(opcode_indicators[tinyram_opcode_STOREB], + memory_subcontents - pb_packing_sum( + pb_variable_array(desval->bits.begin(), + desval->bits.begin() + 8)), + 0), + FMT(this->annotation_prefix, " handle_storeb")); + this->pb.add_r1cs_constraint(r1cs_constraint(opcode_indicators[tinyram_opcode_STOREW], + memory_subcontents - desval->packed, + 0), + FMT(this->annotation_prefix, " handle_storew")); + this->pb.add_r1cs_constraint(r1cs_constraint(1 - (opcode_indicators[tinyram_opcode_STOREB] + opcode_indicators[tinyram_opcode_STOREW]), + ls_prev_val_as_doubleword_variable->packed - ls_next_val_as_doubleword_variable->packed, + 0), + FMT(this->annotation_prefix, " non_store_instructions_dont_change_memory")); + + /* specify that accepting state implies opcode = answer && arg2val == 0 */ + this->pb.add_r1cs_constraint(r1cs_constraint(next_has_accepted, + 1 - opcode_indicators[tinyram_opcode_ANSWER], + 0), + FMT(this->annotation_prefix, " accepting_requires_answer")); + this->pb.add_r1cs_constraint(r1cs_constraint(next_has_accepted, + arg2val->packed, + 0), + FMT(this->annotation_prefix, " accepting_requires_arg2val_equal_zero")); + + /* + handle tapes: + + we require that: + prev_tape1_exhausted implies next_tape1_exhausted, + prev_tape1_exhausted implies flag to be set + reads other than from tape 1 imply flag to be set + flag implies result to be 0 + */ + this->pb.add_r1cs_constraint(r1cs_constraint(prev_tape1_exhausted, + 1 - next_tape1_exhausted, + 0), + FMT(this->annotation_prefix, " prev_tape1_exhausted_implies_next_tape1_exhausted")); + this->pb.add_r1cs_constraint(r1cs_constraint(prev_tape1_exhausted, + 1 - instruction_flags[tinyram_opcode_READ], + 0), + FMT(this->annotation_prefix, " prev_tape1_exhausted_implies_flag")); + this->pb.add_r1cs_constraint(r1cs_constraint(opcode_indicators[tinyram_opcode_READ], + 1 - arg2val->packed, + read_not1), + FMT(this->annotation_prefix, " read_not1")); /* will be nonzero for read X for X != 1 */ + this->pb.add_r1cs_constraint(r1cs_constraint(read_not1, + 1 - instruction_flags[tinyram_opcode_READ], + 0), + FMT(this->annotation_prefix, " other_reads_imply_flag")); + this->pb.add_r1cs_constraint(r1cs_constraint(instruction_flags[tinyram_opcode_READ], + instruction_results[tinyram_opcode_READ], + 0), + FMT(this->annotation_prefix, " read_flag_implies_result_0")); +} + +template +void tinyram_cpu_checker::generate_r1cs_witness_address() +{ + /* decode instruction and arguments */ + prev_pc_addr_as_word_variable->generate_r1cs_witness_from_bits(); + for (size_t i = 0; i < this->pb.ap.k; ++i) + { + prev_registers[i].generate_r1cs_witness_from_bits(); + } + + decode_arguments->generate_r1cs_witness(); + + desval->generate_r1cs_witness_from_packed(); + arg1val->generate_r1cs_witness_from_packed(); + arg2val->generate_r1cs_witness_from_packed(); + + /* clear out ls_addr and fill with everything of arg2val except the subaddress */ + ls_addr.fill_with_bits_of_field_element(this->pb, this->pb.val(arg2val->packed).as_ulong() >> this->pb.ap.subaddr_len()); +} + +template +void tinyram_cpu_checker::generate_r1cs_witness_other(tinyram_input_tape_iterator &aux_it, + const tinyram_input_tape_iterator &aux_end) +{ + /* now ls_prev_val is filled with memory contents at ls_addr. we + now ensure consistency with its doubleword representation */ + ls_prev_val_as_doubleword_variable->generate_r1cs_witness_from_bits(); + + /* fill in the opcode indicators */ + const size_t opcode_val = opcode.get_field_element_from_bits(this->pb).as_ulong(); + for (size_t i = 0; i < 1ul<pb.ap.opcode_width(); ++i) + { + this->pb.val(opcode_indicators[i]) = (i == opcode_val ? FieldT::one() : FieldT::zero()); + } + + /* execute the ALU */ + ALU->generate_r1cs_witness(); + + /* fill memory_subaddress */ + memory_subaddress->bits.fill_with_bits(this->pb, pb_variable_array(arg2val->bits.begin(), + arg2val->bits.begin() + + this->pb.ap.subaddr_len()).get_bits(this->pb)); + memory_subaddress->generate_r1cs_witness_from_bits(); + + /* we distinguish four cases for memory handling: + a) load.b + b) store.b + c) store.w + d) load.w or any non-memory instruction */ + const size_t prev_doubleword = this->pb.val(ls_prev_val_as_doubleword_variable->packed).as_ulong(); + const size_t subaddress = this->pb.val(memory_subaddress->packed).as_ulong(); + + if (this->pb.val(opcode_indicators[tinyram_opcode_LOADB]) == FieldT::one()) + { + const size_t loaded_byte = (prev_doubleword >> (8 * subaddress)) & 0xFF; + this->pb.val(instruction_results[tinyram_opcode_LOADB]) = FieldT(loaded_byte); + this->pb.val(memory_subcontents) = FieldT(loaded_byte); + } + else if (this->pb.val(opcode_indicators[tinyram_opcode_STOREB]) == FieldT::one()) + { + const size_t stored_byte = (this->pb.val(desval->packed).as_ulong()) & 0xFF; + this->pb.val(memory_subcontents) = FieldT(stored_byte); + } + else if (this->pb.val(opcode_indicators[tinyram_opcode_STOREW]) == FieldT::one()) + { + const size_t stored_word = (this->pb.val(desval->packed).as_ulong()); + this->pb.val(memory_subcontents) = FieldT(stored_word); + } + else + { + const bool access_is_word0 = (this->pb.val(*memory_subaddress->bits.rbegin()) == FieldT::zero()); + const size_t loaded_word = (prev_doubleword >> (access_is_word0 ? 0 : this->pb.ap.w)) & ((1ul << this->pb.ap.w) - 1); + this->pb.val(instruction_results[tinyram_opcode_LOADW]) = FieldT(loaded_word); /* does not hurt even for non-memory instructions */ + this->pb.val(memory_subcontents) = FieldT(loaded_word); + } + + memory_access_is_word.evaluate(this->pb); + memory_access_is_byte.evaluate(this->pb); + + check_memory->generate_r1cs_witness(); + + /* handle reads */ + if (this->pb.val(prev_tape1_exhausted) == FieldT::one()) + { + /* if tape was exhausted before, it will always be + exhausted. we also need to only handle reads from tape 1, + so we can safely set flag here */ + this->pb.val(next_tape1_exhausted) = FieldT::one(); + this->pb.val(instruction_flags[tinyram_opcode_READ]) = FieldT::one(); + } + + this->pb.val(read_not1) = this->pb.val(opcode_indicators[tinyram_opcode_READ]) * (FieldT::one() - this->pb.val(arg2val->packed)); + if (this->pb.val(read_not1) != FieldT::one()) + { + /* reading from tape other than 0 raises the flag */ + this->pb.val(instruction_flags[tinyram_opcode_READ]) = FieldT::one(); + } + else + { + /* otherwise perform the actual read */ + if (aux_it != aux_end) + { + this->pb.val(instruction_results[tinyram_opcode_READ]) = FieldT(*aux_it); + if (++aux_it == aux_end) + { + /* tape has ended! */ + this->pb.val(next_tape1_exhausted) = FieldT::one(); + } + } + else + { + /* handled above, so nothing to do here */ + } + } + + /* flag implies result zero */ + if (this->pb.val(instruction_flags[tinyram_opcode_READ]) == FieldT::one()) + { + this->pb.val(instruction_results[tinyram_opcode_READ]) = FieldT::zero(); + } + + /* execute consistency enforcer */ + consistency_enforcer->generate_r1cs_witness(); + next_pc_addr_as_word_variable->generate_r1cs_witness_from_packed(); + + for (size_t i = 0; i < this->pb.ap.k; ++i) + { + next_registers[i].generate_r1cs_witness_from_packed(); + } + + /* finally set has_accepted to 1 if both the opcode is ANSWER and arg2val is 0 */ + this->pb.val(next_has_accepted) = (this->pb.val(opcode_indicators[tinyram_opcode_ANSWER]) == FieldT::one() && + this->pb.val(arg2val->packed) == FieldT::zero()) ? FieldT::one() : FieldT::zero(); +} + +template +void tinyram_cpu_checker::dump() const +{ + printf(" pc = %lu, flag = %lu\n", + this->pb.val(prev_pc_addr_as_word_variable->packed).as_ulong(), + this->pb.val(prev_flag).as_ulong()); + printf(" "); + + for (size_t j = 0; j < this->pb.ap.k; ++j) + { + printf("r%zu = %2lu ", j, this->pb.val(prev_registers[j].packed).as_ulong()); + } + printf("\n"); + + const size_t opcode_val = opcode.get_field_element_from_bits(this->pb).as_ulong(); + printf(" %s r%lu, r%lu, %s%lu\n", + tinyram_opcode_names[static_cast(opcode_val)].c_str(), + desidx.get_field_element_from_bits(this->pb).as_ulong(), + arg1idx.get_field_element_from_bits(this->pb).as_ulong(), + (this->pb.val(arg2_is_imm) == FieldT::one() ? "" : "r"), + arg2idx.get_field_element_from_bits(this->pb).as_ulong()); +} + +} // libsnark + +#endif // TINYRAM_CPU_CHECKER_TCC_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/curves/weierstrass_g1_gadget.hpp b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/curves/weierstrass_g1_gadget.hpp new file mode 100644 index 0000000..337360a --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/curves/weierstrass_g1_gadget.hpp @@ -0,0 +1,153 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for G1 gadgets. + + The gadgets verify curve arithmetic in G1 = E(F) where E/F: y^2 = x^3 + A * X + B + is an elliptic curve over F in short Weierstrass form. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef WEIERSTRASS_G1_GADGET_HPP_ +#define WEIERSTRASS_G1_GADGET_HPP_ + +#include "gadgetlib1/gadget.hpp" +#include "gadgetlib1/gadgets/pairing/pairing_params.hpp" + +namespace libsnark { + +/** + * Gadget that represents a G1 variable. + */ +template +class G1_variable : public gadget > { +public: + typedef Fr FieldT; + + pb_linear_combination X; + pb_linear_combination Y; + + pb_linear_combination_array all_vars; + + G1_variable(protoboard &pb, + const std::string &annotation_prefix); + G1_variable(protoboard &pb, + const G1 > &P, + const std::string &annotation_prefix); + + void generate_r1cs_witness(const G1 > &elt); + + // (See a comment in r1cs_ppzksnark_verifier_gadget.hpp about why + // we mark this function noinline.) TODO: remove later + static size_t __attribute__((noinline)) size_in_bits(); + static size_t num_variables(); +}; + +/** + * Gadget that creates constraints for the validity of a G1 variable. + */ +template +class G1_checker_gadget : public gadget > { +public: + typedef Fr FieldT; + + G1_variable P; + pb_variable P_X_squared; + pb_variable P_Y_squared; + + G1_checker_gadget(protoboard &pb, + const G1_variable &P, + const std::string &annotation_prefix); + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +/** + * Gadget that creates constraints for G1 addition. + */ +template +class G1_add_gadget : public gadget > { +public: + typedef Fr FieldT; + + pb_variable lambda; + pb_variable inv; + + G1_variable A; + G1_variable B; + G1_variable C; + + G1_add_gadget(protoboard &pb, + const G1_variable &A, + const G1_variable &B, + const G1_variable &C, + const std::string &annotation_prefix); + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +/** + * Gadget that creates constraints for G1 doubling. + */ +template +class G1_dbl_gadget : public gadget > { +public: + typedef Fr FieldT; + + pb_variable Xsquared; + pb_variable lambda; + + G1_variable A; + G1_variable B; + + G1_dbl_gadget(protoboard &pb, + const G1_variable &A, + const G1_variable &B, + const std::string &annotation_prefix); + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +/** + * Gadget that creates constraints for G1 multi-scalar multiplication. + */ +template +class G1_multiscalar_mul_gadget : public gadget > { +public: + typedef Fr FieldT; + + std::vector > computed_results; + std::vector > chosen_results; + std::vector > adders; + std::vector > doublers; + + G1_variable base; + pb_variable_array scalars; + std::vector > points; + std::vector > points_and_powers; + G1_variable result; + + const size_t elt_size; + const size_t num_points; + const size_t scalar_size; + + G1_multiscalar_mul_gadget(protoboard &pb, + const G1_variable &base, + const pb_variable_array &scalars, + const size_t elt_size, + const std::vector > &points, + const G1_variable &result, + const std::string &annotation_prefix); + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +} // libsnark + +#include "gadgetlib1/gadgets/curves/weierstrass_g1_gadget.tcc" + +#endif // WEIERSTRASS_G1_GADGET_TCC_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/curves/weierstrass_g1_gadget.tcc b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/curves/weierstrass_g1_gadget.tcc new file mode 100644 index 0000000..d840108 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/curves/weierstrass_g1_gadget.tcc @@ -0,0 +1,326 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for G1 gadgets. + + See weierstrass_g1_gadgets.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef WEIERSTRASS_G1_GADGET_TCC_ +#define WEIERSTRASS_G1_GADGET_TCC_ + +namespace libsnark { + +template +G1_variable::G1_variable(protoboard &pb, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix) +{ + pb_variable X_var, Y_var; + + X_var.allocate(pb, FMT(annotation_prefix, " X")); + Y_var.allocate(pb, FMT(annotation_prefix, " Y")); + + X = pb_linear_combination(X_var); + Y = pb_linear_combination(Y_var); + + all_vars.emplace_back(X); + all_vars.emplace_back(Y); +} + +template +G1_variable::G1_variable(protoboard &pb, + const G1 > &P, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix) +{ + G1 > Pcopy = P; + Pcopy.to_affine_coordinates(); + + X.assign(pb, Pcopy.X()); + Y.assign(pb, Pcopy.Y()); + X.evaluate(pb); + Y.evaluate(pb); + all_vars.emplace_back(X); + all_vars.emplace_back(Y); +} + +template +void G1_variable::generate_r1cs_witness(const G1 > &el) +{ + G1 > el_normalized = el; + el_normalized.to_affine_coordinates(); + + this->pb.lc_val(X) = el_normalized.X(); + this->pb.lc_val(Y) = el_normalized.Y(); +} + +template +size_t G1_variable::size_in_bits() +{ + return 2 * FieldT::size_in_bits(); +} + +template +size_t G1_variable::num_variables() +{ + return 2; +} + +template +G1_checker_gadget::G1_checker_gadget(protoboard &pb, const G1_variable &P, const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), P(P) +{ + P_X_squared.allocate(pb, FMT(annotation_prefix, " P_X_squared")); + P_Y_squared.allocate(pb, FMT(annotation_prefix, " P_Y_squared")); +} + +template +void G1_checker_gadget::generate_r1cs_constraints() +{ + this->pb.add_r1cs_constraint(r1cs_constraint( + { P.X }, + { P.X }, + { P_X_squared }), + FMT(this->annotation_prefix, " P_X_squared")); + this->pb.add_r1cs_constraint(r1cs_constraint( + { P.Y }, + { P.Y }, + { P_Y_squared }), + FMT(this->annotation_prefix, " P_Y_squared")); + this->pb.add_r1cs_constraint(r1cs_constraint( + { P.X }, + { P_X_squared, ONE * G1 >::coeff_a }, + { P_Y_squared, ONE * (-G1 >::coeff_b) }), + FMT(this->annotation_prefix, " curve_equation")); +} + +template +void G1_checker_gadget::generate_r1cs_witness() +{ + this->pb.val(P_X_squared) = this->pb.lc_val(P.X).squared(); + this->pb.val(P_Y_squared) = this->pb.lc_val(P.Y).squared(); +} + +template +G1_add_gadget::G1_add_gadget(protoboard &pb, + const G1_variable &A, + const G1_variable &B, + const G1_variable &C, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), + A(A), + B(B), + C(C) +{ + /* + lambda = (B.y - A.y)/(B.x - A.x) + C.x = lambda^2 - A.x - B.x + C.y = lambda(A.x - C.x) - A.y + + Special cases: + + doubling: if B.y = A.y and B.x = A.x then lambda is unbound and + C = (lambda^2, lambda^3) + + addition of negative point: if B.y = -A.y and B.x = A.x then no + lambda can satisfy the first equation unless B.y - A.y = 0. But + then this reduces to doubling. + + So we need to check that A.x - B.x != 0, which can be done by + enforcing I * (B.x - A.x) = 1 + */ + lambda.allocate(pb, FMT(annotation_prefix, " lambda")); + inv.allocate(pb, FMT(annotation_prefix, " inv")); +} + +template +void G1_add_gadget::generate_r1cs_constraints() +{ + this->pb.add_r1cs_constraint(r1cs_constraint( + { lambda }, + { B.X, A.X * (-1) }, + { B.Y, A.Y * (-1) }), + FMT(this->annotation_prefix, " calc_lambda")); + + this->pb.add_r1cs_constraint(r1cs_constraint( + { lambda }, + { lambda }, + { C.X, A.X, B.X }), + FMT(this->annotation_prefix, " calc_X")); + + this->pb.add_r1cs_constraint(r1cs_constraint( + { lambda }, + { A.X, C.X * (-1) }, + { C.Y, A.Y }), + FMT(this->annotation_prefix, " calc_Y")); + + this->pb.add_r1cs_constraint(r1cs_constraint( + { inv }, + { B.X, A.X * (-1) }, + { ONE }), + FMT(this->annotation_prefix, " no_special_cases")); +} + +template +void G1_add_gadget::generate_r1cs_witness() +{ + this->pb.val(inv) = (this->pb.lc_val(B.X) - this->pb.lc_val(A.X)).inverse(); + this->pb.val(lambda) = (this->pb.lc_val(B.Y) - this->pb.lc_val(A.Y)) * this->pb.val(inv); + this->pb.lc_val(C.X) = this->pb.val(lambda).squared() - this->pb.lc_val(A.X) - this->pb.lc_val(B.X); + this->pb.lc_val(C.Y) = this->pb.val(lambda) * (this->pb.lc_val(A.X) - this->pb.lc_val(C.X)) - this->pb.lc_val(A.Y); +} + +template +G1_dbl_gadget::G1_dbl_gadget(protoboard &pb, + const G1_variable &A, + const G1_variable &B, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), + A(A), + B(B) +{ + Xsquared.allocate(pb, FMT(annotation_prefix, " X_squared")); + lambda.allocate(pb, FMT(annotation_prefix, " lambda")); +} + +template +void G1_dbl_gadget::generate_r1cs_constraints() +{ + this->pb.add_r1cs_constraint(r1cs_constraint( + { A.X }, + { A.X }, + { Xsquared }), + FMT(this->annotation_prefix, " calc_Xsquared")); + + this->pb.add_r1cs_constraint(r1cs_constraint( + { lambda * 2 }, + { A.Y }, + { Xsquared * 3, ONE * G1 >::coeff_a }), + FMT(this->annotation_prefix, " calc_lambda")); + + this->pb.add_r1cs_constraint(r1cs_constraint( + { lambda }, + { lambda }, + { B.X, A.X * 2 }), + FMT(this->annotation_prefix, " calc_X")); + + this->pb.add_r1cs_constraint(r1cs_constraint( + { lambda }, + { A.X, B.X * (-1) }, + { B.Y, A.Y }), + FMT(this->annotation_prefix, " calc_Y")); +} + +template +void G1_dbl_gadget::generate_r1cs_witness() +{ + this->pb.val(Xsquared) = this->pb.lc_val(A.X).squared(); + this->pb.val(lambda) = (FieldT(3) * this->pb.val(Xsquared) + G1 >::coeff_a) * (FieldT(2) * this->pb.lc_val(A.Y)).inverse(); + this->pb.lc_val(B.X) = this->pb.val(lambda).squared() - FieldT(2) * this->pb.lc_val(A.X); + this->pb.lc_val(B.Y) = this->pb.val(lambda) * (this->pb.lc_val(A.X) - this->pb.lc_val(B.X)) - this->pb.lc_val(A.Y); +} + +template +G1_multiscalar_mul_gadget::G1_multiscalar_mul_gadget(protoboard &pb, + const G1_variable &base, + const pb_variable_array &scalars, + const size_t elt_size, + const std::vector > &points, + const G1_variable&result, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), + base(base), + scalars(scalars), + points(points), + result(result), + elt_size(elt_size), + num_points(points.size()), + scalar_size(scalars.size()) +{ + assert(num_points >= 1); + assert(num_points * elt_size == scalar_size); + + for (size_t i = 0; i < num_points; ++i) + { + points_and_powers.emplace_back(points[i]); + for (size_t j = 0; j < elt_size - 1; ++j) + { + points_and_powers.emplace_back(G1_variable(pb, FMT(annotation_prefix, " points_%zu_times_2_to_%zu", i, j+1))); + doublers.emplace_back(G1_dbl_gadget(pb, points_and_powers[i*elt_size + j], points_and_powers[i*elt_size + j + 1], FMT(annotation_prefix, " double_%zu_to_2_to_%zu", i, j+1))); + } + } + + chosen_results.emplace_back(base); + for (size_t i = 0; i < scalar_size; ++i) + { + computed_results.emplace_back(G1_variable(pb, FMT(annotation_prefix, " computed_results_%zu"))); + if (i < scalar_size-1) + { + chosen_results.emplace_back(G1_variable(pb, FMT(annotation_prefix, " chosen_results_%zu"))); + } + else + { + chosen_results.emplace_back(result); + } + + adders.emplace_back(G1_add_gadget(pb, chosen_results[i], points_and_powers[i], computed_results[i], FMT(annotation_prefix, " adders_%zu"))); + } +} + +template +void G1_multiscalar_mul_gadget::generate_r1cs_constraints() +{ + const size_t num_constraints_before = this->pb.num_constraints(); + + for (size_t i = 0; i < scalar_size - num_points; ++i) + { + doublers[i].generate_r1cs_constraints(); + } + + for (size_t i = 0; i < scalar_size; ++i) + { + adders[i].generate_r1cs_constraints(); + + /* + chosen_results[i+1].X = scalars[i] * computed_results[i].X + (1-scalars[i]) * chosen_results[i].X + chosen_results[i+1].X - chosen_results[i].X = scalars[i] * (computed_results[i].X - chosen_results[i].X) + */ + this->pb.add_r1cs_constraint(r1cs_constraint(scalars[i], + computed_results[i].X - chosen_results[i].X, + chosen_results[i+1].X - chosen_results[i].X), + FMT(this->annotation_prefix, " chosen_results_%zu_X", i+1)); + this->pb.add_r1cs_constraint(r1cs_constraint(scalars[i], + computed_results[i].Y - chosen_results[i].Y, + chosen_results[i+1].Y - chosen_results[i].Y), + FMT(this->annotation_prefix, " chosen_results_%zu_Y", i+1)); + } + + const size_t num_constraints_after = this->pb.num_constraints(); + assert(num_constraints_after - num_constraints_before == 4 * (scalar_size-num_points) + (4 + 2) * scalar_size); +} + +template +void G1_multiscalar_mul_gadget::generate_r1cs_witness() +{ + for (size_t i = 0; i < scalar_size - num_points; ++i) + { + doublers[i].generate_r1cs_witness(); + } + + for (size_t i = 0; i < scalar_size; ++i) + { + adders[i].generate_r1cs_witness(); + this->pb.lc_val(chosen_results[i+1].X) = (this->pb.val(scalars[i]) == Fr::zero() ? this->pb.lc_val(chosen_results[i].X) : this->pb.lc_val(computed_results[i].X)); + this->pb.lc_val(chosen_results[i+1].Y) = (this->pb.val(scalars[i]) == Fr::zero() ? this->pb.lc_val(chosen_results[i].Y) : this->pb.lc_val(computed_results[i].Y)); + } +} + +} // libsnark + +#endif // WEIERSTRASS_G1_GADGET_TCC_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/curves/weierstrass_g2_gadget.hpp b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/curves/weierstrass_g2_gadget.hpp new file mode 100644 index 0000000..6310827 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/curves/weierstrass_g2_gadget.hpp @@ -0,0 +1,84 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for G2 gadgets. + + The gadgets verify curve arithmetic in G2 = E'(F) where E'/F^e: y^2 = x^3 + A' * X + B' + is an elliptic curve over F^e in short Weierstrass form. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef WEIERSTRASS_G2_GADGET_HPP_ +#define WEIERSTRASS_G2_GADGET_HPP_ + +#include "gadgetlib1/gadget.hpp" +#include "gadgetlib1/gadgets/pairing/pairing_params.hpp" + +namespace libsnark { + +/** + * Gadget that represents a G2 variable. + */ +template +class G2_variable : public gadget > { +public: + typedef Fr FieldT; + typedef Fqe > FqeT; + typedef Fqk > FqkT; + + std::shared_ptr > X; + std::shared_ptr > Y; + + pb_linear_combination_array all_vars; + + G2_variable(protoboard &pb, + const std::string &annotation_prefix); + G2_variable(protoboard &pb, + const G2 > &Q, + const std::string &annotation_prefix); + + void generate_r1cs_witness(const G2 > &Q); + + // (See a comment in r1cs_ppzksnark_verifier_gadget.hpp about why + // we mark this function noinline.) TODO: remove later + static size_t __attribute__((noinline)) size_in_bits(); + static size_t num_variables(); +}; + +/** + * Gadget that creates constraints for the validity of a G2 variable. + */ +template +class G2_checker_gadget : public gadget > { +public: + typedef Fr FieldT; + typedef Fqe > FqeT; + typedef Fqk > FqkT; + + G2_variable Q; + + std::shared_ptr > Xsquared; + std::shared_ptr > Ysquared; + std::shared_ptr > Xsquared_plus_a; + std::shared_ptr > Ysquared_minus_b; + + std::shared_ptr > compute_Xsquared; + std::shared_ptr > compute_Ysquared; + std::shared_ptr > curve_equation; + + G2_checker_gadget(protoboard &pb, + const G2_variable &Q, + const std::string &annotation_prefix); + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +} // libsnark + +#include "gadgetlib1/gadgets/curves/weierstrass_g2_gadget.tcc" + +#endif // WEIERSTRASS_G2_GADGET_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/curves/weierstrass_g2_gadget.tcc b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/curves/weierstrass_g2_gadget.tcc new file mode 100644 index 0000000..7e5dc48 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/curves/weierstrass_g2_gadget.tcc @@ -0,0 +1,130 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for G2 gadgets. + + See weierstrass_g2_gadgets.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef WEIERSTRASS_G2_GADGET_TCC_ +#define WEIERSTRASS_G2_GADGET_TCC_ + +#include "algebra/scalar_multiplication/wnaf.hpp" + +namespace libsnark { + +template +G2_variable::G2_variable(protoboard &pb, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix) +{ + X.reset(new Fqe_variable(pb, FMT(annotation_prefix, " X"))); + Y.reset(new Fqe_variable(pb, FMT(annotation_prefix, " Y"))); + + all_vars.insert(all_vars.end(), X->all_vars.begin(), X->all_vars.end()); + all_vars.insert(all_vars.end(), Y->all_vars.begin(), Y->all_vars.end()); +} + +template +G2_variable::G2_variable(protoboard &pb, + const G2 > &Q, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix) +{ + G2 > Q_copy = Q; + Q_copy.to_affine_coordinates(); + + X.reset(new Fqe_variable(pb, Q_copy.X(), FMT(annotation_prefix, " X"))); + Y.reset(new Fqe_variable(pb, Q_copy.Y(), FMT(annotation_prefix, " Y"))); + + all_vars.insert(all_vars.end(), X->all_vars.begin(), X->all_vars.end()); + all_vars.insert(all_vars.end(), Y->all_vars.begin(), Y->all_vars.end()); +} + +template +void G2_variable::generate_r1cs_witness(const G2 > &Q) +{ + G2 > Qcopy = Q; + Qcopy.to_affine_coordinates(); + + X->generate_r1cs_witness(Qcopy.X()); + Y->generate_r1cs_witness(Qcopy.Y()); +} + +template +size_t G2_variable::size_in_bits() +{ + return 2 * Fqe_variable::size_in_bits(); +} + +template +size_t G2_variable::num_variables() +{ + return 2 * Fqe_variable::num_variables(); +} + +template +G2_checker_gadget::G2_checker_gadget(protoboard &pb, + const G2_variable &Q, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), + Q(Q) +{ + Xsquared.reset(new Fqe_variable(pb, FMT(annotation_prefix, " Xsquared"))); + Ysquared.reset(new Fqe_variable(pb, FMT(annotation_prefix, " Ysquared"))); + + compute_Xsquared.reset(new Fqe_sqr_gadget(pb, *(Q.X), *Xsquared, FMT(annotation_prefix, " compute_Xsquared"))); + compute_Ysquared.reset(new Fqe_sqr_gadget(pb, *(Q.Y), *Ysquared, FMT(annotation_prefix, " compute_Ysquared"))); + + Xsquared_plus_a.reset(new Fqe_variable((*Xsquared) + G2 >::coeff_a)); + Ysquared_minus_b.reset(new Fqe_variable((*Ysquared) + (-G2 >::coeff_b))); + + curve_equation.reset(new Fqe_mul_gadget(pb, *(Q.X), *Xsquared_plus_a, *Ysquared_minus_b, FMT(annotation_prefix, " curve_equation"))); +} + +template +void G2_checker_gadget::generate_r1cs_constraints() +{ + compute_Xsquared->generate_r1cs_constraints(); + compute_Ysquared->generate_r1cs_constraints(); + curve_equation->generate_r1cs_constraints(); +} + +template +void G2_checker_gadget::generate_r1cs_witness() +{ + compute_Xsquared->generate_r1cs_witness(); + compute_Ysquared->generate_r1cs_witness(); + Xsquared_plus_a->evaluate(); + curve_equation->generate_r1cs_witness(); +} + +template +void test_G2_checker_gadget(const std::string &annotation) +{ + protoboard > pb; + G2_variable g(pb, "g"); + G2_checker_gadget g_check(pb, g, "g_check"); + g_check.generate_r1cs_constraints(); + + printf("positive test\n"); + g.generate_r1cs_witness(G2 >::one()); + g_check.generate_r1cs_witness(); + assert(pb.is_satisfied()); + + printf("negative test\n"); + g.generate_r1cs_witness(G2 >::zero()); + g_check.generate_r1cs_witness(); + assert(!pb.is_satisfied()); + + printf("number of constraints for G2 checker (Fr is %s) = %zu\n", annotation.c_str(), pb.num_constraints()); +} + +} // libsnark + +#endif // WEIERSTRASS_G2_GADGET_TCC_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/delegated_ra_memory/memory_load_gadget.hpp b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/delegated_ra_memory/memory_load_gadget.hpp new file mode 100644 index 0000000..09a4c5b --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/delegated_ra_memory/memory_load_gadget.hpp @@ -0,0 +1,25 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for the memory load gadget. + The gadget can be used to verify a memory load from a "delegated memory". + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef MEMORY_LOAD_GADGET_HPP_ +#define MEMORY_LOAD_GADGET_HPP_ + +#include "gadgetlib1/gadgets/merkle_tree/merkle_tree_check_read_gadget.hpp" + +namespace libsnark { + +template +using memory_load_gadget = merkle_tree_check_read_gadget; + +} // libsnark + +#endif // MEMORY_LOAD_GADGET_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/delegated_ra_memory/memory_load_store_gadget.hpp b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/delegated_ra_memory/memory_load_store_gadget.hpp new file mode 100644 index 0000000..222a1dc --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/delegated_ra_memory/memory_load_store_gadget.hpp @@ -0,0 +1,27 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for the memory load&store gadget. + + The gadget can be used to verify a memory load, followed by a store to the + same address, from a "delegated memory". + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef MEMORY_LOAD_STORE_GADGET_HPP_ +#define MEMORY_LOAD_STORE_GADGET_HPP_ + +#include "gadgetlib1/gadgets/merkle_tree/merkle_tree_check_update_gadget.hpp" + +namespace libsnark { + +template +using memory_load_store_gadget = merkle_tree_check_update_gadget; + +} // libsnark + +#endif // MEMORY_LOAD_STORE_GADGET_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/fields/exponentiation_gadget.hpp b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/fields/exponentiation_gadget.hpp new file mode 100644 index 0000000..f54b786 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/fields/exponentiation_gadget.hpp @@ -0,0 +1,64 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for the exponentiation gadget. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef EXPONENTIATION_GADGET_HPP_ +#define EXPONENTIATION_GADGET_HPP_ + +#include +#include +#include "algebra/fields/bigint.hpp" +#include "algebra/scalar_multiplication/wnaf.hpp" +#include "gadgetlib1/gadget.hpp" + +namespace libsnark { + +/** + * The exponentiation gadget verifies field exponentiation in the field F_{p^k}. + * + * Note that the power is a constant (i.e., hardcoded into the gadget). + */ +template class Fpk_variableT, template class Fpk_mul_gadgetT, template class Fpk_sqr_gadgetT, mp_size_t m> +class exponentiation_gadget : gadget { +public: + typedef typename FpkT::my_Fp FieldT; + std::vector NAF; + + std::vector > > intermediate; + std::vector > > addition_steps; + std::vector > > subtraction_steps; + std::vector > > doubling_steps; + + Fpk_variableT elt; + bigint power; + Fpk_variableT result; + + size_t intermed_count; + size_t add_count; + size_t sub_count; + size_t dbl_count; + + exponentiation_gadget(protoboard &pb, + const Fpk_variableT &elt, + const bigint &power, + const Fpk_variableT &result, + const std::string &annotation_prefix); + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +template class Fpk_variableT, template class Fpk_mul_gadgetT, template class Fpk_sqr_gadgetT, mp_size_t m> +void test_exponentiation_gadget(const bigint &power, const std::string &annotation); + +} // libsnark + +#include "gadgetlib1/gadgets/fields/exponentiation_gadget.tcc" + +#endif // EXPONENTIATION_GADGET_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/fields/exponentiation_gadget.tcc b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/fields/exponentiation_gadget.tcc new file mode 100644 index 0000000..d65f7ac --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/fields/exponentiation_gadget.tcc @@ -0,0 +1,206 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for the exponentiation gadget. + + See exponentiation_gadget.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef EXPONENTIATION_GADGET_TCC_ +#define EXPONENTIATION_GADGET_TCC_ + +namespace libsnark { + +template class Fpk_variableT, template class Fpk_mul_gadgetT, template class Fpk_sqr_gadgetT, mp_size_t m> +exponentiation_gadget::exponentiation_gadget(protoboard &pb, + const Fpk_variableT &elt, + const bigint &power, + const Fpk_variableT &result, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), elt(elt), power(power), result(result) +{ + NAF = find_wnaf(1, power); + + intermed_count = 0; + add_count = 0; + sub_count = 0; + dbl_count = 0; + + bool found_nonzero = false; + for (long i = NAF.size() - 1; i >= 0; --i) + { + if (found_nonzero) + { + ++dbl_count; + ++intermed_count; + } + + if (NAF[i] != 0) + { + found_nonzero = true; + + if (NAF[i] > 0) + { + ++add_count; + ++intermed_count; + } + else + { + ++sub_count; + ++intermed_count; + } + } + } + + intermediate.resize(intermed_count); + intermediate[0].reset(new Fpk_variableT(pb, FpkT::one(), FMT(annotation_prefix, " intermediate_0"))); + for (size_t i = 1; i < intermed_count; ++i) + { + intermediate[i].reset(new Fpk_variableT(pb, FMT(annotation_prefix, " intermediate_%zu", i))); + } + addition_steps.resize(add_count); + subtraction_steps.resize(sub_count); + doubling_steps.resize(dbl_count); + + found_nonzero = false; + + size_t dbl_id = 0, add_id = 0, sub_id = 0, intermed_id = 0; + + for (long i = NAF.size() - 1; i >= 0; --i) + { + if (found_nonzero) + { + doubling_steps[dbl_id].reset(new Fpk_sqr_gadgetT(pb, + *intermediate[intermed_id], + (intermed_id + 1 == intermed_count ? result : *intermediate[intermed_id+1]), + FMT(annotation_prefix, " doubling_steps_%zu", dbl_count))); + ++intermed_id; + ++dbl_id; + } + + if (NAF[i] != 0) + { + found_nonzero = true; + + if (NAF[i] > 0) + { + /* next = cur * elt */ + addition_steps[add_id].reset(new Fpk_mul_gadgetT(pb, + *intermediate[intermed_id], + elt, + (intermed_id + 1 == intermed_count ? result : *intermediate[intermed_id+1]), + FMT(annotation_prefix, " addition_steps_%zu", dbl_count))); + ++add_id; + ++intermed_id; + } + else + { + /* next = cur / elt, i.e. next * elt = cur */ + subtraction_steps[sub_id].reset(new Fpk_mul_gadgetT(pb, + (intermed_id + 1 == intermed_count ? result : *intermediate[intermed_id+1]), + elt, + *intermediate[intermed_id], + FMT(annotation_prefix, " subtraction_steps_%zu", dbl_count))); + ++sub_id; + ++intermed_id; + } + } + } +} + +template class Fpk_variableT, template class Fpk_mul_gadgetT, template class Fpk_sqr_gadgetT, mp_size_t m> +void exponentiation_gadget::generate_r1cs_constraints() +{ + for (size_t i = 0; i < add_count; ++i) + { + addition_steps[i]->generate_r1cs_constraints(); + } + + for (size_t i = 0; i < sub_count; ++i) + { + subtraction_steps[i]->generate_r1cs_constraints(); + } + + for (size_t i = 0; i < dbl_count; ++i) + { + doubling_steps[i]->generate_r1cs_constraints(); + } +} + +template class Fpk_variableT, template class Fpk_mul_gadgetT, template class Fpk_sqr_gadgetT, mp_size_t m> +void exponentiation_gadget::generate_r1cs_witness() +{ + intermediate[0]->generate_r1cs_witness(FpkT::one()); + + bool found_nonzero = false; + size_t dbl_id = 0, add_id = 0, sub_id = 0, intermed_id = 0; + + for (long i = NAF.size() - 1; i >= 0; --i) + { + if (found_nonzero) + { + doubling_steps[dbl_id]->generate_r1cs_witness(); + ++intermed_id; + ++dbl_id; + } + + if (NAF[i] != 0) + { + found_nonzero = true; + + if (NAF[i] > 0) + { + addition_steps[add_id]->generate_r1cs_witness(); + ++intermed_id; + ++add_id; + } + else + { + const FpkT cur_val = intermediate[intermed_id]->get_element(); + const FpkT elt_val = elt.get_element(); + const FpkT next_val = cur_val * elt_val.inverse(); + + (intermed_id + 1 == intermed_count ? result : *intermediate[intermed_id+1]).generate_r1cs_witness(next_val); + + subtraction_steps[sub_id]->generate_r1cs_witness(); + + ++intermed_id; + ++sub_id; + } + } + } +} + +template class Fpk_variableT, template class Fpk_mul_gadgetT, template class Fpk_sqr_gadgetT, mp_size_t m> +void test_exponentiation_gadget(const bigint &power, const std::string &annotation) +{ + typedef typename FpkT::my_Fp FieldT; + + protoboard pb; + Fpk_variableT x(pb, "x"); + Fpk_variableT x_to_power(pb, "x_to_power"); + exponentiation_gadget exp_gadget(pb, x, power, x_to_power, "exp_gadget"); + exp_gadget.generate_r1cs_constraints(); + + for (size_t i = 0; i < 10; ++i) + { + const FpkT x_val = FpkT::random_element(); + x.generate_r1cs_witness(x_val); + exp_gadget.generate_r1cs_witness(); + const FpkT res = x_to_power.get_element(); + assert(pb.is_satisfied()); + assert(res == (x_val ^ power)); + } + printf("number of constraints for %s_exp = %zu\n", annotation.c_str(), pb.num_constraints()); + printf("exponent was: "); + power.print(); +} + +} // libsnark + +#endif // EXPONENTIATION_GADGET_TCC_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/fields/fp2_gadgets.hpp b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/fields/fp2_gadgets.hpp new file mode 100644 index 0000000..ac968fd --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/fields/fp2_gadgets.hpp @@ -0,0 +1,132 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for Fp2 gadgets. + + The gadgets verify field arithmetic in Fp2 = Fp[U]/(U^2-non_residue), + where non_residue is in Fp. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef FP2_GADGETS_HPP_ +#define FP2_GADGETS_HPP_ + +#include "gadgetlib1/gadget.hpp" +#include + +namespace libsnark { + +/** + * Gadget that represents an Fp2 variable. + */ +template +class Fp2_variable : public gadget { +public: + typedef typename Fp2T::my_Fp FieldT; + + pb_linear_combination c0; + pb_linear_combination c1; + + pb_linear_combination_array all_vars; + + Fp2_variable(protoboard &pb, + const std::string &annotation_prefix); + Fp2_variable(protoboard &pb, + const Fp2T &el, + const std::string &annotation_prefix); + Fp2_variable(protoboard &pb, + const Fp2T &el, + const pb_linear_combination &coeff, + const std::string &annotation_prefix); + Fp2_variable(protoboard &pb, + const pb_linear_combination &c0, + const pb_linear_combination &c1, + const std::string &annotation_prefix); + + void generate_r1cs_equals_const_constraints(const Fp2T &el); + void generate_r1cs_witness(const Fp2T &el); + Fp2T get_element(); + + Fp2_variable operator*(const FieldT &coeff) const; + Fp2_variable operator+(const Fp2_variable &other) const; + Fp2_variable operator+(const Fp2T &other) const; + Fp2_variable mul_by_X() const; + void evaluate() const; + bool is_constant() const; + + static size_t size_in_bits(); + static size_t num_variables(); +}; + +/** + * Gadget that creates constraints for Fp2 by Fp2 multiplication. + */ +template +class Fp2_mul_gadget : public gadget { +public: + typedef typename Fp2T::my_Fp FieldT; + + Fp2_variable A; + Fp2_variable B; + Fp2_variable result; + + pb_variable v1; + + Fp2_mul_gadget(protoboard &pb, + const Fp2_variable &A, + const Fp2_variable &B, + const Fp2_variable &result, + const std::string &annotation_prefix); + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +/** + * Gadget that creates constraints for Fp2 multiplication by a linear combination. + */ +template +class Fp2_mul_by_lc_gadget : public gadget { +public: + typedef typename Fp2T::my_Fp FieldT; + + Fp2_variable A; + pb_linear_combination lc; + Fp2_variable result; + + Fp2_mul_by_lc_gadget(protoboard &pb, + const Fp2_variable &A, + const pb_linear_combination &lc, + const Fp2_variable &result, + const std::string &annotation_prefix); + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +/** + * Gadget that creates constraints for Fp2 squaring. + */ +template +class Fp2_sqr_gadget : public gadget { +public: + typedef typename Fp2T::my_Fp FieldT; + + Fp2_variable A; + Fp2_variable result; + + Fp2_sqr_gadget(protoboard &pb, + const Fp2_variable &A, + const Fp2_variable &result, + const std::string &annotation_prefix); + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +} // libsnark + +#include "gadgetlib1/gadgets/fields/fp2_gadgets.tcc" + +#endif // FP2_GADGETS_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/fields/fp2_gadgets.tcc b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/fields/fp2_gadgets.tcc new file mode 100644 index 0000000..2b080c2 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/fields/fp2_gadgets.tcc @@ -0,0 +1,281 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for Fp2 gadgets. + + See fp2_gadgets.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef FP2_GADGETS_TCC_ +#define FP2_GADGETS_TCC_ + +namespace libsnark { + +template +Fp2_variable::Fp2_variable(protoboard &pb, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix) +{ + pb_variable c0_var, c1_var; + c0_var.allocate(pb, FMT(annotation_prefix, " c0")); + c1_var.allocate(pb, FMT(annotation_prefix, " c1")); + + c0 = pb_linear_combination(c0_var); + c1 = pb_linear_combination(c1_var); + + all_vars.emplace_back(c0); + all_vars.emplace_back(c1); +} + +template +Fp2_variable::Fp2_variable(protoboard &pb, + const Fp2T &el, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix) +{ + c0.assign(pb, el.c0); + c1.assign(pb, el.c1); + + c0.evaluate(pb); + c1.evaluate(pb); + + all_vars.emplace_back(c0); + all_vars.emplace_back(c1); +} + +template +Fp2_variable::Fp2_variable(protoboard &pb, + const Fp2T &el, + const pb_linear_combination &coeff, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix) +{ + c0.assign(pb, el.c0 * coeff); + c1.assign(pb, el.c1 * coeff); + + all_vars.emplace_back(c0); + all_vars.emplace_back(c1); +} + +template +Fp2_variable::Fp2_variable(protoboard &pb, + const pb_linear_combination &c0, + const pb_linear_combination &c1, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), c0(c0), c1(c1) +{ + all_vars.emplace_back(c0); + all_vars.emplace_back(c1); +} + +template +void Fp2_variable::generate_r1cs_equals_const_constraints(const Fp2T &el) +{ + this->pb.add_r1cs_constraint(r1cs_constraint(1, el.c0, c0), + FMT(this->annotation_prefix, " c0")); + this->pb.add_r1cs_constraint(r1cs_constraint(1, el.c1, c1), + FMT(this->annotation_prefix, " c1")); +} + +template +void Fp2_variable::generate_r1cs_witness(const Fp2T &el) +{ + this->pb.lc_val(c0) = el.c0; + this->pb.lc_val(c1) = el.c1; +} + +template +Fp2T Fp2_variable::get_element() +{ + Fp2T el; + el.c0 = this->pb.lc_val(c0); + el.c1 = this->pb.lc_val(c1); + return el; +} + +template +Fp2_variable Fp2_variable::operator*(const FieldT &coeff) const +{ + pb_linear_combination new_c0, new_c1; + new_c0.assign(this->pb, this->c0 * coeff); + new_c1.assign(this->pb, this->c1 * coeff); + return Fp2_variable(this->pb, new_c0, new_c1, FMT(this->annotation_prefix, " operator*")); +} + +template +Fp2_variable Fp2_variable::operator+(const Fp2_variable &other) const +{ + pb_linear_combination new_c0, new_c1; + new_c0.assign(this->pb, this->c0 + other.c0); + new_c1.assign(this->pb, this->c1 + other.c1); + return Fp2_variable(this->pb, new_c0, new_c1, FMT(this->annotation_prefix, " operator+")); +} + +template +Fp2_variable Fp2_variable::operator+(const Fp2T &other) const +{ + pb_linear_combination new_c0, new_c1; + new_c0.assign(this->pb, this->c0 + other.c0); + new_c1.assign(this->pb, this->c1 + other.c1); + return Fp2_variable(this->pb, new_c0, new_c1, FMT(this->annotation_prefix, " operator+")); +} + +template +Fp2_variable Fp2_variable::mul_by_X() const +{ + pb_linear_combination new_c0, new_c1; + new_c0.assign(this->pb, this->c1 * Fp2T::non_residue); + new_c1.assign(this->pb, this->c0); + return Fp2_variable(this->pb, new_c0, new_c1, FMT(this->annotation_prefix, " mul_by_X")); +} + +template +void Fp2_variable::evaluate() const +{ + c0.evaluate(this->pb); + c1.evaluate(this->pb); +} + +template +bool Fp2_variable::is_constant() const +{ + return (c0.is_constant() && c1.is_constant()); +} + +template +size_t Fp2_variable::size_in_bits() +{ + return 2 * FieldT::size_in_bits(); +} + +template +size_t Fp2_variable::num_variables() +{ + return 2; +} + +template +Fp2_mul_gadget::Fp2_mul_gadget(protoboard &pb, + const Fp2_variable &A, + const Fp2_variable &B, + const Fp2_variable &result, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), A(A), B(B), result(result) +{ + v1.allocate(pb, FMT(annotation_prefix, " v1")); +} + +template +void Fp2_mul_gadget::generate_r1cs_constraints() +{ +/* + Karatsuba multiplication for Fp2: + v0 = A.c0 * B.c0 + v1 = A.c1 * B.c1 + result.c0 = v0 + non_residue * v1 + result.c1 = (A.c0 + A.c1) * (B.c0 + B.c1) - v0 - v1 + + Enforced with 3 constraints: + A.c1 * B.c1 = v1 + A.c0 * B.c0 = result.c0 - non_residue * v1 + (A.c0+A.c1)*(B.c0+B.c1) = result.c1 + result.c0 + (1 - non_residue) * v1 + + Reference: + "Multiplication and Squaring on Pairing-Friendly Fields" + Devegili, OhEigeartaigh, Scott, Dahab +*/ + this->pb.add_r1cs_constraint(r1cs_constraint(A.c1, B.c1, v1), + FMT(this->annotation_prefix, " v1")); + this->pb.add_r1cs_constraint(r1cs_constraint(A.c0, B.c0, result.c0 + v1 * (-Fp2T::non_residue)), + FMT(this->annotation_prefix, " result.c0")); + this->pb.add_r1cs_constraint(r1cs_constraint(A.c0 + A.c1, B.c0 + B.c1, + result.c1 + result.c0 + v1 * (FieldT::one() - Fp2T::non_residue)), + FMT(this->annotation_prefix, " result.c1")); +} + +template +void Fp2_mul_gadget::generate_r1cs_witness() +{ + const FieldT aA = this->pb.lc_val(A.c0) * this->pb.lc_val(B.c0); + this->pb.val(v1) = this->pb.lc_val(A.c1) * this->pb.lc_val(B.c1); + this->pb.lc_val(result.c0) = aA + Fp2T::non_residue * this->pb.val(v1); + this->pb.lc_val(result.c1) = (this->pb.lc_val(A.c0) + this->pb.lc_val(A.c1)) * (this->pb.lc_val(B.c0) + this->pb.lc_val(B.c1)) - aA - this->pb.lc_val(v1); +} + +template +Fp2_mul_by_lc_gadget::Fp2_mul_by_lc_gadget(protoboard &pb, + const Fp2_variable &A, + const pb_linear_combination &lc, + const Fp2_variable &result, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), A(A), lc(lc), result(result) +{ +} + +template +void Fp2_mul_by_lc_gadget::generate_r1cs_constraints() +{ + this->pb.add_r1cs_constraint(r1cs_constraint(A.c0, lc, result.c0), + FMT(this->annotation_prefix, " result.c0")); + this->pb.add_r1cs_constraint(r1cs_constraint(A.c1, lc, result.c1), + FMT(this->annotation_prefix, " result.c1")); +} + +template +void Fp2_mul_by_lc_gadget::generate_r1cs_witness() +{ + this->pb.lc_val(result.c0) = this->pb.lc_val(A.c0) * this->pb.lc_val(lc); + this->pb.lc_val(result.c1) = this->pb.lc_val(A.c1) * this->pb.lc_val(lc); +} + +template +Fp2_sqr_gadget::Fp2_sqr_gadget(protoboard &pb, + const Fp2_variable &A, + const Fp2_variable &result, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), A(A), result(result) +{ +} + +template +void Fp2_sqr_gadget::generate_r1cs_constraints() +{ +/* + Complex multiplication for Fp2: + v0 = A.c0 * A.c1 + result.c0 = (A.c0 + A.c1) * (A.c0 + non_residue * A.c1) - (1 + non_residue) * v0 + result.c1 = 2 * v0 + + Enforced with 2 constraints: + (2*A.c0) * A.c1 = result.c1 + (A.c0 + A.c1) * (A.c0 + non_residue * A.c1) = result.c0 + result.c1 * (1 + non_residue)/2 + + Reference: + "Multiplication and Squaring on Pairing-Friendly Fields" + Devegili, OhEigeartaigh, Scott, Dahab +*/ + this->pb.add_r1cs_constraint(r1cs_constraint(2 * A.c0, A.c1, result.c1), + FMT(this->annotation_prefix, " result.c1")); + this->pb.add_r1cs_constraint(r1cs_constraint(A.c0 + A.c1, + A.c0 + Fp2T::non_residue * A.c1, + result.c0 + result.c1 * (FieldT::one() + Fp2T::non_residue) * FieldT(2).inverse()), + FMT(this->annotation_prefix, " result.c0")); +} + +template +void Fp2_sqr_gadget::generate_r1cs_witness() +{ + const FieldT a = this->pb.lc_val(A.c0); + const FieldT b = this->pb.lc_val(A.c1); + this->pb.lc_val(result.c1) = FieldT(2) * a * b; + this->pb.lc_val(result.c0) = (a + b) * (a + Fp2T::non_residue * b) - a*b - Fp2T::non_residue * a* b; +} + +} // libsnark + +#endif // FP2_GADGETS_TCC_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/fields/fp3_gadgets.hpp b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/fields/fp3_gadgets.hpp new file mode 100644 index 0000000..4a6f4b1 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/fields/fp3_gadgets.hpp @@ -0,0 +1,135 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for Fp3 gadgets. + + The gadgets verify field arithmetic in Fp3 = Fp[U]/(U^3-non_residue), + where non_residue is in Fp. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef FP3_GADGETS_HPP_ +#define FP3_GADGETS_HPP_ + +namespace libsnark { + +/** + * Gadget that represents an Fp3 variable. + */ +template +class Fp3_variable : public gadget { +public: + typedef typename Fp3T::my_Fp FieldT; + + pb_linear_combination c0; + pb_linear_combination c1; + pb_linear_combination c2; + + pb_linear_combination_array all_vars; + + Fp3_variable(protoboard &pb, + const std::string &annotation_prefix); + Fp3_variable(protoboard &pb, + const Fp3T &el, + const std::string &annotation_prefix); + Fp3_variable(protoboard &pb, + const Fp3T &el, + const pb_linear_combination &coeff, + const std::string &annotation_prefix); + Fp3_variable(protoboard &pb, + const pb_linear_combination &c0, + const pb_linear_combination &c1, + const pb_linear_combination &c2, + const std::string &annotation_prefix); + + void generate_r1cs_equals_const_constraints(const Fp3T &el); + void generate_r1cs_witness(const Fp3T &el); + Fp3T get_element(); + + Fp3_variable operator*(const FieldT &coeff) const; + Fp3_variable operator+(const Fp3_variable &other) const; + Fp3_variable operator+(const Fp3T &other) const; + Fp3_variable mul_by_X() const; + void evaluate() const; + bool is_constant() const; + + static size_t size_in_bits(); + static size_t num_variables(); +}; + +/** + * Gadget that creates constraints for Fp3 by Fp3 multiplication. + */ +template +class Fp3_mul_gadget : public gadget { +public: + typedef typename Fp3T::my_Fp FieldT; + + Fp3_variable A; + Fp3_variable B; + Fp3_variable result; + + pb_variable v0; + pb_variable v4; + + Fp3_mul_gadget(protoboard &pb, + const Fp3_variable &A, + const Fp3_variable &B, + const Fp3_variable &result, + const std::string &annotation_prefix); + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +/** + * Gadget that creates constraints for Fp3 multiplication by a linear combination. + */ +template +class Fp3_mul_by_lc_gadget : public gadget { +public: + typedef typename Fp3T::my_Fp FieldT; + + Fp3_variable A; + pb_linear_combination lc; + Fp3_variable result; + + Fp3_mul_by_lc_gadget(protoboard &pb, + const Fp3_variable &A, + const pb_linear_combination &lc, + const Fp3_variable &result, + const std::string &annotation_prefix); + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +/** + * Gadget that creates constraints for Fp3 squaring. + */ +template +class Fp3_sqr_gadget : public gadget { +public: + typedef typename Fp3T::my_Fp FieldT; + + Fp3_variable A; + Fp3_variable result; + + std::shared_ptr > mul; + + Fp3_sqr_gadget(protoboard &pb, + const Fp3_variable &A, + const Fp3_variable &result, + const std::string &annotation_prefix); + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + + +} // libsnark + +#include "gadgetlib1/gadgets/fields/fp3_gadgets.tcc" + +#endif // FP3_GADGETS_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/fields/fp3_gadgets.tcc b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/fields/fp3_gadgets.tcc new file mode 100644 index 0000000..22b1df5 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/fields/fp3_gadgets.tcc @@ -0,0 +1,316 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for Fp3 gadgets. + + See fp3_gadgets.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef FP3_GADGETS_TCC_ +#define FP3_GADGETS_TCC_ + +namespace libsnark { + +template +Fp3_variable::Fp3_variable(protoboard &pb, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix) +{ + pb_variable c0_var, c1_var, c2_var; + c0_var.allocate(pb, FMT(annotation_prefix, " c0")); + c1_var.allocate(pb, FMT(annotation_prefix, " c1")); + c2_var.allocate(pb, FMT(annotation_prefix, " c2")); + + c0 = pb_linear_combination(c0_var); + c1 = pb_linear_combination(c1_var); + c2 = pb_linear_combination(c2_var); + + all_vars.emplace_back(c0); + all_vars.emplace_back(c1); + all_vars.emplace_back(c2); +} + +template +Fp3_variable::Fp3_variable(protoboard &pb, + const Fp3T &el, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix) +{ + c0.assign(pb, el.c0); + c1.assign(pb, el.c1); + c2.assign(pb, el.c2); + + c0.evaluate(pb); + c1.evaluate(pb); + c2.evaluate(pb); + + all_vars.emplace_back(c0); + all_vars.emplace_back(c1); + all_vars.emplace_back(c2); +} + +template +Fp3_variable::Fp3_variable(protoboard &pb, + const Fp3T &el, + const pb_linear_combination &coeff, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix) +{ + c0.assign(pb, el.c0 * coeff); + c1.assign(pb, el.c1 * coeff); + c2.assign(pb, el.c2 * coeff); + + all_vars.emplace_back(c0); + all_vars.emplace_back(c1); + all_vars.emplace_back(c2); +} + +template +Fp3_variable::Fp3_variable(protoboard &pb, + const pb_linear_combination &c0, + const pb_linear_combination &c1, + const pb_linear_combination &c2, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), c0(c0), c1(c1), c2(c2) +{ + all_vars.emplace_back(c0); + all_vars.emplace_back(c1); + all_vars.emplace_back(c2); +} + +template +void Fp3_variable::generate_r1cs_equals_const_constraints(const Fp3T &el) +{ + this->pb.add_r1cs_constraint(r1cs_constraint(1, el.c0, c0), + FMT(this->annotation_prefix, " c0")); + this->pb.add_r1cs_constraint(r1cs_constraint(1, el.c1, c1), + FMT(this->annotation_prefix, " c1")); + this->pb.add_r1cs_constraint(r1cs_constraint(1, el.c2, c2), + FMT(this->annotation_prefix, " c2")); +} + +template +void Fp3_variable::generate_r1cs_witness(const Fp3T &el) +{ + this->pb.lc_val(c0) = el.c0; + this->pb.lc_val(c1) = el.c1; + this->pb.lc_val(c2) = el.c2; +} + +template +Fp3T Fp3_variable::get_element() +{ + Fp3T el; + el.c0 = this->pb.lc_val(c0); + el.c1 = this->pb.lc_val(c1); + el.c2 = this->pb.lc_val(c2); + return el; +} + +template +Fp3_variable Fp3_variable::operator*(const FieldT &coeff) const +{ + pb_linear_combination new_c0, new_c1, new_c2; + new_c0.assign(this->pb, this->c0 * coeff); + new_c1.assign(this->pb, this->c1 * coeff); + new_c2.assign(this->pb, this->c2 * coeff); + return Fp3_variable(this->pb, new_c0, new_c1, new_c2, FMT(this->annotation_prefix, " operator*")); +} + +template +Fp3_variable Fp3_variable::operator+(const Fp3_variable &other) const +{ + pb_linear_combination new_c0, new_c1, new_c2; + new_c0.assign(this->pb, this->c0 + other.c0); + new_c1.assign(this->pb, this->c1 + other.c1); + new_c2.assign(this->pb, this->c2 + other.c2); + return Fp3_variable(this->pb, new_c0, new_c1, new_c2, FMT(this->annotation_prefix, " operator+")); +} + +template +Fp3_variable Fp3_variable::operator+(const Fp3T &other) const +{ + pb_linear_combination new_c0, new_c1, new_c2; + new_c0.assign(this->pb, this->c0 + other.c0); + new_c1.assign(this->pb, this->c1 + other.c1); + new_c2.assign(this->pb, this->c2 + other.c2); + return Fp3_variable(this->pb, new_c0, new_c1, new_c2, FMT(this->annotation_prefix, " operator+")); +} + +template +Fp3_variable Fp3_variable::mul_by_X() const +{ + pb_linear_combination new_c0, new_c1, new_c2; + new_c0.assign(this->pb, this->c2 * Fp3T::non_residue); + new_c1.assign(this->pb, this->c0); + new_c2.assign(this->pb, this->c1); + return Fp3_variable(this->pb, new_c0, new_c1, new_c2, FMT(this->annotation_prefix, " mul_by_X")); +} + +template +void Fp3_variable::evaluate() const +{ + c0.evaluate(this->pb); + c1.evaluate(this->pb); + c2.evaluate(this->pb); +} + +template +bool Fp3_variable::is_constant() const +{ + return (c0.is_constant() && c1.is_constant() && c2.is_constant()); +} + +template +size_t Fp3_variable::size_in_bits() +{ + return 3 * FieldT::size_in_bits(); +} + +template +size_t Fp3_variable::num_variables() +{ + return 3; +} + +template +Fp3_mul_gadget::Fp3_mul_gadget(protoboard &pb, + const Fp3_variable &A, + const Fp3_variable &B, + const Fp3_variable &result, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), A(A), B(B), result(result) +{ + v0.allocate(pb, FMT(annotation_prefix, " v0")); + v4.allocate(pb, FMT(annotation_prefix, " v4")); +} + +template +void Fp3_mul_gadget::generate_r1cs_constraints() +{ +/* + Tom-Cook-3x for Fp3: + v0 = A.c0 * B.c0 + v1 = (A.c0 + A.c1 + A.c2) * (B.c0 + B.c1 + B.c2) + v2 = (A.c0 - A.c1 + A.c2) * (B.c0 - B.c1 + B.c2) + v3 = (A.c0 + 2*A.c1 + 4*A.c2) * (B.c0 + 2*B.c1 + 4*B.c2) + v4 = A.c2 * B.c2 + result.c0 = v0 + non_residue * (v0/2 - v1/2 - v2/6 + v3/6 - 2*v4) + result.c1 = -(1/2) v0 + v1 - (1/3) v2 - (1/6) v3 + 2 v4 + non_residue*v4 + result.c2 = -v0 + (1/2) v1 + (1/2) v2 - v4 + + Enforced with 5 constraints. Doing so requires some care, as we first + compute two of the v_i explicitly, and then "inline" result.c1/c2/c3 + in computations of teh remaining three v_i. + + Concretely, we first compute v0 and v4 explicitly, via 2 constraints: + A.c0 * B.c0 = v0 + A.c2 * B.c2 = v4 + Then we use the following 3 additional constraints: + v1 = result.c1 + result.c2 + (result.c0 - v0)/non_residue + v0 + v4 - non_residue v4 + v2 = -result.c1 + result.c2 + v0 + (-result.c0 + v0)/non_residue + v4 + non_residue v4 + v3 = 2 * result.c1 + 4 result.c2 + (8*(result.c0 - v0))/non_residue + v0 + 16 * v4 - 2 * non_residue * v4 + + Reference: + "Multiplication and Squaring on Pairing-Friendly Fields" + Devegili, OhEigeartaigh, Scott, Dahab + + NOTE: the expressions above were cherry-picked from the Mathematica result + of the following command: + + (# -> Solve[{c0 == v0 + non_residue*(v0/2 - v1/2 - v2/6 + v3/6 - 2 v4), + c1 == -(1/2) v0 + v1 - (1/3) v2 - (1/6) v3 + 2 v4 + non_residue*v4, + c2 == -v0 + (1/2) v1 + (1/2) v2 - v4}, #] // FullSimplify) & /@ + Subsets[{v0, v1, v2, v3, v4}, {3}] +*/ + this->pb.add_r1cs_constraint(r1cs_constraint(A.c0, B.c0, v0), FMT(this->annotation_prefix, " v0")); + this->pb.add_r1cs_constraint(r1cs_constraint(A.c2, B.c2, v4), FMT(this->annotation_prefix, " v4")); + + const FieldT beta = Fp3T::non_residue; + + this->pb.add_r1cs_constraint(r1cs_constraint(A.c0 + A.c1 + A.c2, + B.c0 + B.c1 + B.c2, + result.c1 + result.c2 + result.c0 * beta.inverse() + v0 * (FieldT(1) - beta.inverse()) + v4 * (FieldT(1) - beta)), + FMT(this->annotation_prefix, " v1")); + this->pb.add_r1cs_constraint(r1cs_constraint(A.c0 - A.c1 + A.c2, + B.c0 - B.c1 + B.c2, + -result.c1 + result.c2 + v0 * (FieldT(1) + beta.inverse()) - result.c0 * beta.inverse() + v4 * (FieldT(1) + beta)), + FMT(this->annotation_prefix, " v2")); + this->pb.add_r1cs_constraint(r1cs_constraint(A.c0 + 2 * A.c1 + 4 * A.c2, + B.c0 + 2 * B.c1 + 4 * B.c2, + 2 * result.c1 + 4 * result.c2 + result.c0 * (FieldT(8) * beta.inverse()) + v0 * (FieldT(1) - FieldT(8) * beta.inverse()) + v4 * (FieldT(16) - FieldT(2) * beta)), + FMT(this->annotation_prefix, " v3")); +} + +template +void Fp3_mul_gadget::generate_r1cs_witness() +{ + this->pb.val(v0) = this->pb.lc_val(A.c0) * this->pb.lc_val(B.c0); + this->pb.val(v4) = this->pb.lc_val(A.c2) * this->pb.lc_val(B.c2); + + const Fp3T Aval = A.get_element(); + const Fp3T Bval = B.get_element(); + const Fp3T Rval = Aval * Bval; + result.generate_r1cs_witness(Rval); +} + +template +Fp3_mul_by_lc_gadget::Fp3_mul_by_lc_gadget(protoboard &pb, + const Fp3_variable &A, + const pb_linear_combination &lc, + const Fp3_variable &result, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), A(A), lc(lc), result(result) +{ +} + +template +void Fp3_mul_by_lc_gadget::generate_r1cs_constraints() +{ + this->pb.add_r1cs_constraint(r1cs_constraint(A.c0, lc, result.c0), + FMT(this->annotation_prefix, " result.c0")); + this->pb.add_r1cs_constraint(r1cs_constraint(A.c1, lc, result.c1), + FMT(this->annotation_prefix, " result.c1")); + this->pb.add_r1cs_constraint(r1cs_constraint(A.c2, lc, result.c2), + FMT(this->annotation_prefix, " result.c2")); +} + +template +void Fp3_mul_by_lc_gadget::generate_r1cs_witness() +{ + this->pb.lc_val(result.c0) = this->pb.lc_val(A.c0) * this->pb.lc_val(lc); + this->pb.lc_val(result.c1) = this->pb.lc_val(A.c1) * this->pb.lc_val(lc); + this->pb.lc_val(result.c2) = this->pb.lc_val(A.c2) * this->pb.lc_val(lc); +} + +template +Fp3_sqr_gadget::Fp3_sqr_gadget(protoboard &pb, + const Fp3_variable &A, + const Fp3_variable &result, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), A(A), result(result) +{ + mul.reset(new Fp3_mul_gadget(pb, A, A, result, FMT(annotation_prefix, " mul"))); +} + +template +void Fp3_sqr_gadget::generate_r1cs_constraints() +{ + // We can't do better than 5 constraints for squaring, so we just use multiplication. + mul->generate_r1cs_constraints(); +} + +template +void Fp3_sqr_gadget::generate_r1cs_witness() +{ + mul->generate_r1cs_witness(); +} + +} // libsnark + +#endif // FP3_GADGETS_TCC_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/fields/fp4_gadgets.hpp b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/fields/fp4_gadgets.hpp new file mode 100644 index 0000000..6ff79fa --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/fields/fp4_gadgets.hpp @@ -0,0 +1,200 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for Fp4 gadgets. + + The gadgets verify field arithmetic in Fp4 = Fp2[V]/(V^2-U) where + Fp2 = Fp[U]/(U^2-non_residue) and non_residue is in Fp. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef FP4_GADGETS_HPP_ +#define FP4_GADGETS_HPP_ + +namespace libsnark { + +/** + * Gadget that represents an Fp4 variable. + */ +template +class Fp4_variable : public gadget { +public: + typedef typename Fp4T::my_Fp FieldT; + typedef typename Fp4T::my_Fpe Fp2T; + + Fp2_variable c0; + Fp2_variable c1; + + Fp4_variable(protoboard &pb, const std::string &annotation_prefix); + Fp4_variable(protoboard &pb, const Fp4T &el, const std::string &annotation_prefix); + Fp4_variable(protoboard &pb, const Fp2_variable &c0, const Fp2_variable &c1, const std::string &annotation_prefix); + void generate_r1cs_equals_const_constraints(const Fp4T &el); + void generate_r1cs_witness(const Fp4T &el); + Fp4T get_element(); + + Fp4_variable Frobenius_map(const size_t power) const; + void evaluate() const; +}; + +/** + * Gadget that creates constraints for Fp4 multiplication (towering formulas). + */ +template +class Fp4_tower_mul_gadget : public gadget { +public: + typedef typename Fp4T::my_Fp FieldT; + typedef typename Fp4T::my_Fpe Fp2T; + + Fp4_variable A; + Fp4_variable B; + Fp4_variable result; + + pb_linear_combination v0_c0; + pb_linear_combination v0_c1; + + pb_linear_combination Ac0_plus_Ac1_c0; + pb_linear_combination Ac0_plus_Ac1_c1; + std::shared_ptr > Ac0_plus_Ac1; + + std::shared_ptr > v0; + std::shared_ptr > v1; + + pb_linear_combination Bc0_plus_Bc1_c0; + pb_linear_combination Bc0_plus_Bc1_c1; + std::shared_ptr > Bc0_plus_Bc1; + + pb_linear_combination result_c1_plus_v0_plus_v1_c0; + pb_linear_combination result_c1_plus_v0_plus_v1_c1; + + std::shared_ptr > result_c1_plus_v0_plus_v1; + + std::shared_ptr > compute_v0; + std::shared_ptr > compute_v1; + std::shared_ptr > compute_result_c1; + + Fp4_tower_mul_gadget(protoboard &pb, + const Fp4_variable &A, + const Fp4_variable &B, + const Fp4_variable &result, + const std::string &annotation_prefix); + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +/** + * Gadget that creates constraints for Fp4 multiplication (direct formulas). + */ +template +class Fp4_direct_mul_gadget : public gadget { +public: + typedef typename Fp4T::my_Fp FieldT; + typedef typename Fp4T::my_Fpe Fp2T; + + Fp4_variable A; + Fp4_variable B; + Fp4_variable result; + + pb_variable v1; + pb_variable v2; + pb_variable v6; + + Fp4_direct_mul_gadget(protoboard &pb, + const Fp4_variable &A, + const Fp4_variable &B, + const Fp4_variable &result, + const std::string &annotation_prefix); + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +/** + * Alias default multiplication gadget + */ +template +using Fp4_mul_gadget = Fp4_direct_mul_gadget; + +/** + * Gadget that creates constraints for Fp4 squaring. + */ +template +class Fp4_sqr_gadget : public gadget { +public: + typedef typename Fp4T::my_Fp FieldT; + typedef typename Fp4T::my_Fpe Fp2T; + + Fp4_variable A; + Fp4_variable result; + + std::shared_ptr > v1; + + pb_linear_combination v0_c0; + pb_linear_combination v0_c1; + std::shared_ptr > v0; + + std::shared_ptr > compute_v0; + std::shared_ptr > compute_v1; + + pb_linear_combination Ac0_plus_Ac1_c0; + pb_linear_combination Ac0_plus_Ac1_c1; + std::shared_ptr > Ac0_plus_Ac1; + + pb_linear_combination result_c1_plus_v0_plus_v1_c0; + pb_linear_combinationresult_c1_plus_v0_plus_v1_c1; + + std::shared_ptr > result_c1_plus_v0_plus_v1; + + std::shared_ptr > compute_result_c1; + + Fp4_sqr_gadget(protoboard &pb, + const Fp4_variable &A, + const Fp4_variable &result, + const std::string &annotation_prefix); + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +/** + * Gadget that creates constraints for Fp4 cyclotomic squaring + */ +template +class Fp4_cyclotomic_sqr_gadget : public gadget { +public: +/* +*/ + typedef typename Fp4T::my_Fp FieldT; + typedef typename Fp4T::my_Fpe Fp2T; + + Fp4_variable A; + Fp4_variable result; + + pb_linear_combination c0_expr_c0; + pb_linear_combination c0_expr_c1; + std::shared_ptr > c0_expr; + std::shared_ptr > compute_c0_expr; + + pb_linear_combination A_c0_plus_A_c1_c0; + pb_linear_combination A_c0_plus_A_c1_c1; + std::shared_ptr > A_c0_plus_A_c1; + + pb_linear_combination c1_expr_c0; + pb_linear_combination c1_expr_c1; + std::shared_ptr > c1_expr; + std::shared_ptr > compute_c1_expr; + + Fp4_cyclotomic_sqr_gadget(protoboard &pb, + const Fp4_variable &A, + const Fp4_variable &result, + const std::string &annotation_prefix); + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +} // libsnark + +#include "gadgetlib1/gadgets/fields/fp4_gadgets.tcc" + +#endif // FP4_GADGETS_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/fields/fp4_gadgets.tcc b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/fields/fp4_gadgets.tcc new file mode 100644 index 0000000..5ba1727 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/fields/fp4_gadgets.tcc @@ -0,0 +1,434 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for Fp4 gadgets. + + See fp4_gadgets.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef FP4_GADGETS_TCC_ +#define FP4_GADGETS_TCC_ + +namespace libsnark { + +template +Fp4_variable::Fp4_variable(protoboard &pb, const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), c0(pb, FMT(annotation_prefix, " c0")), c1(pb, FMT(annotation_prefix, " c1")) +{ +} + +template +Fp4_variable::Fp4_variable(protoboard &pb, + const Fp4T &el, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), c0(pb, el.c0, FMT(annotation_prefix, " c0")), c1(pb, el.c1, FMT(annotation_prefix, " c1")) +{ +} + +template +Fp4_variable::Fp4_variable(protoboard &pb, const Fp2_variable &c0, const Fp2_variable &c1, const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), c0(c0), c1(c1) +{ +} + +template +void Fp4_variable::generate_r1cs_equals_const_constraints(const Fp4T &el) +{ + c0.generate_r1cs_equals_const_constraints(el.c0); + c1.generate_r1cs_equals_const_constraints(el.c1); +} + +template +void Fp4_variable::generate_r1cs_witness(const Fp4T &el) +{ + c0.generate_r1cs_witness(el.c0); + c1.generate_r1cs_witness(el.c1); +} + +template +Fp4T Fp4_variable::get_element() +{ + Fp4T el; + el.c0 = c0.get_element(); + el.c1 = c1.get_element(); + return el; +} + +template +Fp4_variable Fp4_variable::Frobenius_map(const size_t power) const +{ + pb_linear_combination new_c0c0, new_c0c1, new_c1c0, new_c1c1; + new_c0c0.assign(this->pb, c0.c0); + new_c0c1.assign(this->pb, c0.c1 * Fp2T::Frobenius_coeffs_c1[power % 2]); + new_c1c0.assign(this->pb, c1.c0 * Fp4T::Frobenius_coeffs_c1[power % 4]); + new_c1c1.assign(this->pb, c1.c1 * Fp4T::Frobenius_coeffs_c1[power % 4] * Fp2T::Frobenius_coeffs_c1[power % 2]); + + return Fp4_variable(this->pb, + Fp2_variable(this->pb, new_c0c0, new_c0c1, FMT(this->annotation_prefix, " Frobenius_map_c0")), + Fp2_variable(this->pb, new_c1c0, new_c1c1, FMT(this->annotation_prefix, " Frobenius_map_c1")), + FMT(this->annotation_prefix, " Frobenius_map")); +} + +template +void Fp4_variable::evaluate() const +{ + c0.evaluate(); + c1.evaluate(); +} + +template +Fp4_tower_mul_gadget::Fp4_tower_mul_gadget(protoboard &pb, + const Fp4_variable &A, + const Fp4_variable &B, + const Fp4_variable &result, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), A(A), B(B), result(result) +{ +/* + Karatsuba multiplication for Fp4 as a quadratic extension of Fp2: + v0 = A.c0 * B.c0 + v1 = A.c1 * B.c1 + result.c0 = v0 + non_residue * v1 + result.c1 = (A.c0 + A.c1) * (B.c0 + B.c1) - v0 - v1 + where "non_residue * elem" := (non_residue * elt.c1, elt.c0) + + Enforced with 3 Fp2_mul_gadget's that ensure that: + A.c1 * B.c1 = v1 + A.c0 * B.c0 = v0 + (A.c0+A.c1)*(B.c0+B.c1) = result.c1 + v0 + v1 + + Reference: + "Multiplication and Squaring on Pairing-Friendly Fields" + Devegili, OhEigeartaigh, Scott, Dahab +*/ + v1.reset(new Fp2_variable(pb, FMT(annotation_prefix, " v1"))); + + compute_v1.reset(new Fp2_mul_gadget(pb, A.c1, B.c1, *v1, FMT(annotation_prefix, " compute_v1"))); + + v0_c0.assign(pb, result.c0.c0 - Fp4T::non_residue * v1->c1); + v0_c1.assign(pb, result.c0.c1 - v1->c0); + v0.reset(new Fp2_variable(pb, v0_c0, v0_c1, FMT(annotation_prefix, " v0"))); + + compute_v0.reset(new Fp2_mul_gadget(pb, A.c0, B.c0, *v0, FMT(annotation_prefix, " compute_v0"))); + + Ac0_plus_Ac1_c0.assign(pb, A.c0.c0 + A.c1.c0); + Ac0_plus_Ac1_c1.assign(pb, A.c0.c1 + A.c1.c1); + Ac0_plus_Ac1.reset(new Fp2_variable(pb, Ac0_plus_Ac1_c0, Ac0_plus_Ac1_c1, FMT(annotation_prefix, " Ac0_plus_Ac1"))); + + Bc0_plus_Bc1_c0.assign(pb, B.c0.c0 + B.c1.c0); + Bc0_plus_Bc1_c1.assign(pb, B.c0.c1 + B.c1.c1); + Bc0_plus_Bc1.reset(new Fp2_variable(pb, Bc0_plus_Bc1_c0, Bc0_plus_Bc1_c1, FMT(annotation_prefix, " Bc0_plus_Bc1"))); + + result_c1_plus_v0_plus_v1_c0.assign(pb, result.c1.c0 + v0->c0 + v1->c0); + result_c1_plus_v0_plus_v1_c1.assign(pb, result.c1.c1 + v0->c1 + v1->c1); + result_c1_plus_v0_plus_v1.reset(new Fp2_variable(pb, result_c1_plus_v0_plus_v1_c0, result_c1_plus_v0_plus_v1_c1, FMT(annotation_prefix, " result_c1_plus_v0_plus_v1"))); + + compute_result_c1.reset(new Fp2_mul_gadget(pb, *Ac0_plus_Ac1, *Bc0_plus_Bc1, *result_c1_plus_v0_plus_v1, FMT(annotation_prefix, " compute_result_c1"))); +} + +template +void Fp4_tower_mul_gadget::generate_r1cs_constraints() +{ + compute_v0->generate_r1cs_constraints(); + compute_v1->generate_r1cs_constraints(); + compute_result_c1->generate_r1cs_constraints(); +} + +template +void Fp4_tower_mul_gadget::generate_r1cs_witness() +{ + compute_v0->generate_r1cs_witness(); + compute_v1->generate_r1cs_witness(); + + Ac0_plus_Ac1_c0.evaluate(this->pb); + Ac0_plus_Ac1_c1.evaluate(this->pb); + + Bc0_plus_Bc1_c0.evaluate(this->pb); + Bc0_plus_Bc1_c1.evaluate(this->pb); + + compute_result_c1->generate_r1cs_witness(); + + const Fp4T Aval = A.get_element(); + const Fp4T Bval = B.get_element(); + const Fp4T Rval = Aval * Bval; + + result.generate_r1cs_witness(Rval); +} + +template +Fp4_direct_mul_gadget::Fp4_direct_mul_gadget(protoboard &pb, + const Fp4_variable &A, + const Fp4_variable &B, + const Fp4_variable &result, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), A(A), B(B), result(result) +{ +/* + Tom-Cook-4x for Fp4 (beta is the quartic non-residue): + v0 = a0*b0, + v1 = (a0+a1+a2+a3)*(b0+b1+b2+b3), + v2 = (a0-a1+a2-a3)*(b0-b1+b2-b3), + v3 = (a0+2a1+4a2+8a3)*(b0+2b1+4b2+8b3), + v4 = (a0-2a1+4a2-8a3)*(b0-2b1+4b2-8b3), + v5 = (a0+3a1+9a2+27a3)*(b0+3b1+9b2+27b3), + v6 = a3*b3 + + result.c0 = v0+beta((1/4)v0-(1/6)(v1+v2)+(1/24)(v3+v4)-5v6), + result.c1 = -(1/3)v0+v1-(1/2)v2-(1/4)v3+(1/20)v4+(1/30)v5-12v6+beta(-(1/12)(v0-v1)+(1/24)(v2-v3)-(1/120)(v4-v5)-3v6), + result.c2 = -(5/4)v0+(2/3)(v1+v2)-(1/24)(v3+v4)+4v6+beta v6, + result.c3 = (1/12)(5v0-7v1)-(1/24)(v2-7v3+v4+v5)+15v6 + + Enforced with 7 constraints. Doing so requires some care, as we first + compute three of the v_i explicitly, and then "inline" result.c0/c1/c2/c3 + in computations of the remaining four v_i. + + Concretely, we first compute v1, v2 and v6 explicitly, via 3 constraints as above. + v1 = (a0+a1+a2+a3)*(b0+b1+b2+b3), + v2 = (a0-a1+a2-a3)*(b0-b1+b2-b3), + v6 = a3*b3 + + Then we use the following 4 additional constraints: + (1-beta) v0 = c0 + beta c2 - (beta v1)/2 - (beta v2)/ 2 - (-1 + beta) beta v6 + (1-beta) v3 = -15 c0 - 30 c1 - 3 (4 + beta) c2 - 6 (4 + beta) c3 + (24 - (3 beta)/2) v1 + (-8 + beta/2) v2 + 3 (-16 + beta) (-1 + beta) v6 + (1-beta) v4 = -15 c0 + 30 c1 - 3 (4 + beta) c2 + 6 (4 + beta) c3 + (-8 + beta/2) v1 + (24 - (3 beta)/2) v2 + 3 (-16 + beta) (-1 + beta) v6 + (1-beta) v5 = -80 c0 - 240 c1 - 8 (9 + beta) c2 - 24 (9 + beta) c3 - 2 (-81 + beta) v1 + (-81 + beta) v2 + 8 (-81 + beta) (-1 + beta) v6 + + The isomorphism between the representation above and towering is: + (a0, a1, a2, a3) <-> (a.c0.c0, a.c1.c0, a.c0.c1, a.c1.c1) + + Reference: + "Multiplication and Squaring on Pairing-Friendly Fields" + Devegili, OhEigeartaigh, Scott, Dahab + + NOTE: the expressions above were cherry-picked from the Mathematica result + of the following command: + + (# -> Solve[{c0 == v0+beta((1/4)v0-(1/6)(v1+v2)+(1/24)(v3+v4)-5v6), + c1 == -(1/3)v0+v1-(1/2)v2-(1/4)v3+(1/20)v4+(1/30)v5-12v6+beta(-(1/12)(v0-v1)+(1/24)(v2-v3)-(1/120)(v4-v5)-3v6), + c2 == -(5/4)v0+(2/3)(v1+v2)-(1/24)(v3+v4)+4v6+beta v6, + c3 == (1/12)(5v0-7v1)-(1/24)(v2-7v3+v4+v5)+15v6}, #] // FullSimplify) & /@ Subsets[{v0, v1, v2, v3, v4, v5}, {4}] + + and simplified by multiplying the selected result by (1-beta) +*/ + v1.allocate(pb, FMT(annotation_prefix, " v1")); + v2.allocate(pb, FMT(annotation_prefix, " v2")); + v6.allocate(pb, FMT(annotation_prefix, " v6")); +} + +template +void Fp4_direct_mul_gadget::generate_r1cs_constraints() +{ + const FieldT beta = Fp4T::non_residue; + const FieldT u = (FieldT::one() - beta).inverse(); + + const pb_linear_combination + &a0 = A.c0.c0, &a1 = A.c1.c0, &a2 = A.c0.c1, &a3 = A.c1.c1, + &b0 = B.c0.c0, &b1 = B.c1.c0, &b2 = B.c0.c1, &b3 = B.c1.c1, + &c0 = result.c0.c0, &c1 = result.c1.c0, &c2 = result.c0.c1, &c3 = result.c1.c1; + + this->pb.add_r1cs_constraint(r1cs_constraint( + a0 + a1 + a2 + a3, + b0 + b1 + b2 + b3, + v1), + FMT(this->annotation_prefix, " v1")); + this->pb.add_r1cs_constraint(r1cs_constraint( + a0 - a1 + a2 - a3, + b0 - b1 + b2 - b3, + v2), + FMT(this->annotation_prefix, " v2")); + this->pb.add_r1cs_constraint(r1cs_constraint( + a3, + b3, + v6), + FMT(this->annotation_prefix, " v6")); + + this->pb.add_r1cs_constraint(r1cs_constraint( + a0, + b0, + u * c0 + beta * u * c2 - beta * u * FieldT(2).inverse() * v1 - beta * u * FieldT(2).inverse() * v2 + beta * v6), + FMT(this->annotation_prefix, " v0")); + this->pb.add_r1cs_constraint(r1cs_constraint( + a0 + FieldT(2)*a1 + FieldT(4)*a2 + FieldT(8)*a3, + b0 + FieldT(2)*b1 + FieldT(4)*b2 + FieldT(8)*b3, + - FieldT(15) * u * c0 - FieldT(30) * u * c1 - FieldT(3) * (FieldT(4) + beta) * u * c2 - FieldT(6) * (FieldT(4) + beta) * u * c3 + (FieldT(24) - FieldT(3) * beta * FieldT(2).inverse()) * u * v1 + (-FieldT(8) + beta * FieldT(2).inverse()) * u * v2 - FieldT(3) * (-FieldT(16) + beta) * v6), + FMT(this->annotation_prefix, " v3")); + this->pb.add_r1cs_constraint(r1cs_constraint( + a0 - FieldT(2)*a1 + FieldT(4)*a2 - FieldT(8)*a3, + b0 - FieldT(2)*b1 + FieldT(4)*b2 - FieldT(8)*b3, + - FieldT(15) * u * c0 + FieldT(30) * u * c1 - FieldT(3) * (FieldT(4) + beta) * u * c2 + FieldT(6) * (FieldT(4) + beta) * u * c3 + (FieldT(24) - FieldT(3) * beta * FieldT(2).inverse()) * u * v2 + (-FieldT(8) + beta * FieldT(2).inverse()) * u * v1 + - FieldT(3) * (-FieldT(16) + beta) * v6), + FMT(this->annotation_prefix, " v4")); + this->pb.add_r1cs_constraint(r1cs_constraint( + a0 + FieldT(3)*a1 + FieldT(9)*a2 + FieldT(27)*a3, + b0 + FieldT(3)*b1 + FieldT(9)*b2 + FieldT(27)*b3, + - FieldT(80) * u * c0 - FieldT(240) * u * c1 - FieldT(8) * (FieldT(9) + beta) * u * c2 - FieldT(24) * (FieldT(9) + beta) * u * c3 - FieldT(2) * (-FieldT(81) + beta) * u * v1 + (-FieldT(81) + beta) * u * v2 - FieldT(8) * (-FieldT(81) + beta) * v6), + FMT(this->annotation_prefix, " v5")); +} + +template +void Fp4_direct_mul_gadget::generate_r1cs_witness() +{ + const pb_linear_combination + &a0 = A.c0.c0, &a1 = A.c1.c0, &a2 = A.c0.c1, &a3 = A.c1.c1, + &b0 = B.c0.c0, &b1 = B.c1.c0, &b2 = B.c0.c1, &b3 = B.c1.c1; + + this->pb.val(v1) = ((this->pb.lc_val(a0) + this->pb.lc_val(a1) + this->pb.lc_val(a2) + this->pb.lc_val(a3)) * + (this->pb.lc_val(b0) + this->pb.lc_val(b1) + this->pb.lc_val(b2) + this->pb.lc_val(b3))); + this->pb.val(v2) = ((this->pb.lc_val(a0) - this->pb.lc_val(a1) + this->pb.lc_val(a2) - this->pb.lc_val(a3)) * + (this->pb.lc_val(b0) - this->pb.lc_val(b1) + this->pb.lc_val(b2) - this->pb.lc_val(b3))); + this->pb.val(v6) = this->pb.lc_val(a3) * this->pb.lc_val(b3); + + const Fp4T Aval = A.get_element(); + const Fp4T Bval = B.get_element(); + const Fp4T Rval = Aval * Bval; + + result.generate_r1cs_witness(Rval); +} + +template +Fp4_sqr_gadget::Fp4_sqr_gadget(protoboard &pb, + const Fp4_variable &A, + const Fp4_variable &result, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), A(A), result(result) +{ +/* + Karatsuba squaring for Fp4 as a quadratic extension of Fp2: + v0 = A.c0^2 + v1 = A.c1^2 + result.c0 = v0 + non_residue * v1 + result.c1 = (A.c0 + A.c1)^2 - v0 - v1 + where "non_residue * elem" := (non_residue * elt.c1, elt.c0) + + Enforced with 3 Fp2_sqr_gadget's that ensure that: + A.c1^2 = v1 + A.c0^2 = v0 + (A.c0+A.c1)^2 = result.c1 + v0 + v1 + + Reference: + "Multiplication and Squaring on Pairing-Friendly Fields" + Devegili, OhEigeartaigh, Scott, Dahab +*/ + v1.reset(new Fp2_variable(pb, FMT(annotation_prefix, " v1"))); + compute_v1.reset(new Fp2_sqr_gadget(pb, A.c1, *v1, FMT(annotation_prefix, " compute_v1"))); + + v0_c0.assign(pb, result.c0.c0 - Fp4T::non_residue * v1->c1); + v0_c1.assign(pb, result.c0.c1 - v1->c0); + v0.reset(new Fp2_variable(pb, v0_c0, v0_c1, FMT(annotation_prefix, " v0"))); + + compute_v0.reset(new Fp2_sqr_gadget(pb, A.c0, *v0, FMT(annotation_prefix, " compute_v0"))); + + Ac0_plus_Ac1_c0.assign(pb, A.c0.c0 + A.c1.c0); + Ac0_plus_Ac1_c1.assign(pb, A.c0.c1 + A.c1.c1); + Ac0_plus_Ac1.reset(new Fp2_variable(pb, Ac0_plus_Ac1_c0, Ac0_plus_Ac1_c1, FMT(annotation_prefix, " Ac0_plus_Ac1"))); + + result_c1_plus_v0_plus_v1_c0.assign(pb, result.c1.c0 + v0->c0 + v1->c0); + result_c1_plus_v0_plus_v1_c1.assign(pb, result.c1.c1 + v0->c1 + v1->c1); + result_c1_plus_v0_plus_v1.reset(new Fp2_variable(pb, result_c1_plus_v0_plus_v1_c0, result_c1_plus_v0_plus_v1_c1, FMT(annotation_prefix, " result_c1_plus_v0_plus_v1"))); + + compute_result_c1.reset(new Fp2_sqr_gadget(pb, *Ac0_plus_Ac1, *result_c1_plus_v0_plus_v1, FMT(annotation_prefix, " compute_result_c1"))); +} + +template +void Fp4_sqr_gadget::generate_r1cs_constraints() +{ + compute_v1->generate_r1cs_constraints(); + compute_v0->generate_r1cs_constraints(); + compute_result_c1->generate_r1cs_constraints(); +} + +template +void Fp4_sqr_gadget::generate_r1cs_witness() +{ + compute_v1->generate_r1cs_witness(); + + v0_c0.evaluate(this->pb); + v0_c1.evaluate(this->pb); + compute_v0->generate_r1cs_witness(); + + Ac0_plus_Ac1_c0.evaluate(this->pb); + Ac0_plus_Ac1_c1.evaluate(this->pb); + compute_result_c1->generate_r1cs_witness(); + + const Fp4T Aval = A.get_element(); + const Fp4T Rval = Aval.squared(); + result.generate_r1cs_witness(Rval); +} + +template +Fp4_cyclotomic_sqr_gadget::Fp4_cyclotomic_sqr_gadget(protoboard &pb, + const Fp4_variable &A, + const Fp4_variable &result, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), A(A), result(result) +{ +/* + A = elt.c1 ^ 2 + B = elt.c1 + elt.c0; + C = B ^ 2 - A + D = Fp2(A.c1 * non_residue, A.c0) + E = C - D + F = D + D + Fp2::one() + G = E - Fp2::one() + + return Fp4(F, G); + + Enforced with 2 Fp2_sqr_gadget's that ensure that: + + elt.c1 ^ 2 = Fp2(result.c0.c1 / 2, (result.c0.c0 - 1) / (2 * non_residue)) = A + (elt.c1 + elt.c0) ^ 2 = A + result.c1 + Fp2(A.c1 * non_residue + 1, A.c0) + + (elt.c1 + elt.c0) ^ 2 = Fp2(result.c0.c1 / 2 + result.c1.c0 + (result.c0.c0 - 1) / 2 + 1, + (result.c0.c0 - 1) / (2 * non_residue) + result.c1.c1 + result.c0.c1 / 2) + + Corresponding test code: + + assert(B.squared() == A + G + my_Fp2(A.c1 * non_residue + my_Fp::one(), A.c0)); + assert(this->c1.squared().c0 == F.c1 * my_Fp(2).inverse()); + assert(this->c1.squared().c1 == (F.c0 - my_Fp(1)) * (my_Fp(2) * non_residue).inverse()); +*/ + c0_expr_c0.assign(pb, result.c0.c1 * FieldT(2).inverse()); + c0_expr_c1.assign(pb, (result.c0.c0 - FieldT(1)) * (FieldT(2) * Fp4T::non_residue).inverse()); + c0_expr.reset(new Fp2_variable(pb, c0_expr_c0, c0_expr_c1, FMT(annotation_prefix, " c0_expr"))); + compute_c0_expr.reset(new Fp2_sqr_gadget(pb, A.c1, *c0_expr, FMT(annotation_prefix, " compute_c0_expr"))); + + A_c0_plus_A_c1_c0.assign(pb, A.c0.c0 + A.c1.c0); + A_c0_plus_A_c1_c1.assign(pb, A.c0.c1 + A.c1.c1); + A_c0_plus_A_c1.reset(new Fp2_variable(pb, A_c0_plus_A_c1_c0, A_c0_plus_A_c1_c1, FMT(annotation_prefix, " A_c0_plus_A_c1"))); + + c1_expr_c0.assign(pb, (result.c0.c1 + result.c0.c0 - FieldT(1)) * FieldT(2).inverse() + result.c1.c0 + FieldT(1)); + c1_expr_c1.assign(pb, (result.c0.c0 - FieldT(1)) * (FieldT(2) * Fp4T::non_residue).inverse() + result.c1.c1 + result.c0.c1 * FieldT(2).inverse()); + c1_expr.reset(new Fp2_variable(pb, c1_expr_c0, c1_expr_c1, FMT(annotation_prefix, " c1_expr"))); + + compute_c1_expr.reset(new Fp2_sqr_gadget(pb, *A_c0_plus_A_c1, *c1_expr, FMT(annotation_prefix, " compute_c1_expr"))); +} + +template +void Fp4_cyclotomic_sqr_gadget::generate_r1cs_constraints() +{ + compute_c0_expr->generate_r1cs_constraints(); + compute_c1_expr->generate_r1cs_constraints(); +} + +template +void Fp4_cyclotomic_sqr_gadget::generate_r1cs_witness() +{ + compute_c0_expr->generate_r1cs_witness(); + + A_c0_plus_A_c1_c0.evaluate(this->pb); + A_c0_plus_A_c1_c1.evaluate(this->pb); + compute_c1_expr->generate_r1cs_witness(); + + const Fp4T Aval = A.get_element(); + const Fp4T Rval = Aval.squared(); + result.generate_r1cs_witness(Rval); +} + +} // libsnark + +#endif // FP4_GADGETS_TCC_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/fields/fp6_gadgets.hpp b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/fields/fp6_gadgets.hpp new file mode 100644 index 0000000..efb978b --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/fields/fp6_gadgets.hpp @@ -0,0 +1,205 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for Fp6 gadgets. + + The gadgets verify field arithmetic in Fp6 = Fp3[Y]/(Y^2-X) where + Fp3 = Fp[X]/(X^3-non_residue) and non_residue is in Fp. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef FP6_GADGETS_HPP_ +#define FP6_GADGETS_HPP_ + +#include "gadgetlib1/gadgets/fields/fp2_gadgets.hpp" + +namespace libsnark { + +/** + * Gadget that represents an Fp6 variable. + */ +template +class Fp6_variable : public gadget { +public: + typedef typename Fp6T::my_Fp FieldT; + typedef typename Fp6T::my_Fpe Fp3T; + + Fp3_variable c0; + Fp3_variable c1; + + Fp6_variable(protoboard &pb, const std::string &annotation_prefix); + Fp6_variable(protoboard &pb, const Fp6T &el, const std::string &annotation_prefix); + Fp6_variable(protoboard &pb, const Fp3_variable &c0, const Fp3_variable &c1, const std::string &annotation_prefix); + void generate_r1cs_equals_const_constraints(const Fp6T &el); + void generate_r1cs_witness(const Fp6T &el); + Fp6T get_element(); + Fp6_variable Frobenius_map(const size_t power) const; + void evaluate() const; +}; + +/** + * Gadget that creates constraints for Fp6 multiplication. + */ +template +class Fp6_mul_gadget : public gadget { +public: + typedef typename Fp6T::my_Fp FieldT; + typedef typename Fp6T::my_Fpe Fp3T; + + Fp6_variable A; + Fp6_variable B; + Fp6_variable result; + + pb_linear_combination v0_c0; + pb_linear_combination v0_c1; + pb_linear_combination v0_c2; + + pb_linear_combination Ac0_plus_Ac1_c0; + pb_linear_combination Ac0_plus_Ac1_c1; + pb_linear_combination Ac0_plus_Ac1_c2; + std::shared_ptr > Ac0_plus_Ac1; + + std::shared_ptr > v0; + std::shared_ptr > v1; + + pb_linear_combination Bc0_plus_Bc1_c0; + pb_linear_combination Bc0_plus_Bc1_c1; + pb_linear_combination Bc0_plus_Bc1_c2; + std::shared_ptr > Bc0_plus_Bc1; + + pb_linear_combination result_c1_plus_v0_plus_v1_c0; + pb_linear_combination result_c1_plus_v0_plus_v1_c1; + pb_linear_combination result_c1_plus_v0_plus_v1_c2; + std::shared_ptr > result_c1_plus_v0_plus_v1; + + std::shared_ptr > compute_v0; + std::shared_ptr > compute_v1; + std::shared_ptr > compute_result_c1; + + Fp6_mul_gadget(protoboard &pb, + const Fp6_variable &A, + const Fp6_variable &B, + const Fp6_variable &result, + const std::string &annotation_prefix); + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +/** + * Gadget that creates constraints for Fp6 multiplication by a Fp6 element B for which B.c0.c0 = B.c0.c1 = 0. + */ +template +class Fp6_mul_by_2345_gadget : public gadget { +public: + typedef typename Fp6T::my_Fp FieldT; + typedef typename Fp6T::my_Fpe Fp3T; + + Fp6_variable A; + Fp6_variable B; + Fp6_variable result; + + pb_linear_combination v0_c0; + pb_linear_combination v0_c1; + pb_linear_combination v0_c2; + + pb_linear_combination Ac0_plus_Ac1_c0; + pb_linear_combination Ac0_plus_Ac1_c1; + pb_linear_combination Ac0_plus_Ac1_c2; + std::shared_ptr > Ac0_plus_Ac1; + + std::shared_ptr > v0; + std::shared_ptr > v1; + + pb_linear_combination Bc0_plus_Bc1_c0; + pb_linear_combination Bc0_plus_Bc1_c1; + pb_linear_combination Bc0_plus_Bc1_c2; + std::shared_ptr > Bc0_plus_Bc1; + + pb_linear_combination result_c1_plus_v0_plus_v1_c0; + pb_linear_combination result_c1_plus_v0_plus_v1_c1; + pb_linear_combination result_c1_plus_v0_plus_v1_c2; + std::shared_ptr > result_c1_plus_v0_plus_v1; + + std::shared_ptr > compute_v1; + std::shared_ptr > compute_result_c1; + + Fp6_mul_by_2345_gadget(protoboard &pb, + const Fp6_variable &A, + const Fp6_variable &B, + const Fp6_variable &result, + const std::string &annotation_prefix); + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +/** + * Gadget that creates constraints for Fp6 squaring. + */ +template +class Fp6_sqr_gadget : public gadget { +public: + typedef typename Fp6T::my_Fp FieldT; + + Fp6_variable A; + Fp6_variable result; + + std::shared_ptr > mul; + + Fp6_sqr_gadget(protoboard &pb, + const Fp6_variable &A, + const Fp6_variable &result, + const std::string &annotation_prefix); + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +/** + * Gadget that creates constraints for Fp6 cyclotomic squaring + */ +template +class Fp6_cyclotomic_sqr_gadget : public gadget { +public: + typedef typename Fp6T::my_Fp FieldT; + typedef typename Fp6T::my_Fp2 Fp2T; + + Fp6_variable A; + Fp6_variable result; + + std::shared_ptr > a; + std::shared_ptr > b; + std::shared_ptr > c; + + pb_linear_combination asq_c0; + pb_linear_combination asq_c1; + + pb_linear_combination bsq_c0; + pb_linear_combination bsq_c1; + + pb_linear_combination csq_c0; + pb_linear_combination csq_c1; + + std::shared_ptr > asq; + std::shared_ptr > bsq; + std::shared_ptr > csq; + + std::shared_ptr > compute_asq; + std::shared_ptr > compute_bsq; + std::shared_ptr > compute_csq; + + Fp6_cyclotomic_sqr_gadget(protoboard &pb, + const Fp6_variable &A, + const Fp6_variable &result, + const std::string &annotation_prefix); + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +} // libsnark + +#include "gadgetlib1/gadgets/fields/fp6_gadgets.tcc" + +#endif // FP6_GADGETS_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/fields/fp6_gadgets.tcc b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/fields/fp6_gadgets.tcc new file mode 100644 index 0000000..62cb43b --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/fields/fp6_gadgets.tcc @@ -0,0 +1,396 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for Fp6 gadgets. + + See fp6_gadgets.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef FP6_GADGETS_TCC_ +#define FP6_GADGETS_TCC_ + +namespace libsnark { + +template +Fp6_variable::Fp6_variable(protoboard &pb, const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), c0(pb, FMT(annotation_prefix, " c0")), c1(pb, FMT(annotation_prefix, " c1")) +{ +} + +template +Fp6_variable::Fp6_variable(protoboard &pb, + const Fp6T &el, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), c0(pb, el.c0, FMT(annotation_prefix, " c0")), c1(pb, el.c1, FMT(annotation_prefix, " c1")) +{ +} + +template +Fp6_variable::Fp6_variable(protoboard &pb, const Fp3_variable &c0, const Fp3_variable &c1, const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), c0(c0), c1(c1) +{ +} + +template +void Fp6_variable::generate_r1cs_equals_const_constraints(const Fp6T &el) +{ + c0.generate_r1cs_equals_const_constraints(el.c0); + c1.generate_r1cs_equals_const_constraints(el.c1); +} + +template +void Fp6_variable::generate_r1cs_witness(const Fp6T &el) +{ + c0.generate_r1cs_witness(el.c0); + c1.generate_r1cs_witness(el.c1); +} + +template +Fp6T Fp6_variable::get_element() +{ + Fp6T el; + el.c0 = c0.get_element(); + el.c1 = c1.get_element(); + return el; +} + +template +Fp6_variable Fp6_variable::Frobenius_map(const size_t power) const +{ + pb_linear_combination new_c0c0, new_c0c1, new_c0c2, new_c1c0, new_c1c1, new_c1c2; + new_c0c0.assign(this->pb, c0.c0); + new_c0c1.assign(this->pb, c0.c1 * Fp3T::Frobenius_coeffs_c1[power % 3]); + new_c0c2.assign(this->pb, c0.c2 * Fp3T::Frobenius_coeffs_c2[power % 3]); + new_c1c0.assign(this->pb, c1.c0 * Fp6T::Frobenius_coeffs_c1[power % 6]); + new_c1c1.assign(this->pb, c1.c1 * (Fp6T::Frobenius_coeffs_c1[power % 6] * Fp3T::Frobenius_coeffs_c1[power % 3])); + new_c1c2.assign(this->pb, c1.c2 * (Fp6T::Frobenius_coeffs_c1[power % 6] * Fp3T::Frobenius_coeffs_c2[power % 3])); + + return Fp6_variable(this->pb, + Fp3_variable(this->pb, new_c0c0, new_c0c1, new_c0c2, FMT(this->annotation_prefix, " Frobenius_map_c0")), + Fp3_variable(this->pb, new_c1c0, new_c1c1, new_c1c2, FMT(this->annotation_prefix, " Frobenius_map_c1")), + FMT(this->annotation_prefix, " Frobenius_map")); +} + +template +void Fp6_variable::evaluate() const +{ + c0.evaluate(); + c1.evaluate(); +} + +template +Fp6_mul_gadget::Fp6_mul_gadget(protoboard &pb, + const Fp6_variable &A, + const Fp6_variable &B, + const Fp6_variable &result, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), A(A), B(B), result(result) +{ +/* + Karatsuba multiplication for Fp6 as a quadratic extension of Fp3: + v0 = A.c0 * B.c0 + v1 = A.c1 * B.c1 + result.c0 = v0 + non_residue * v1 + result.c1 = (A.c0 + A.c1) * (B.c0 + B.c1) - v0 - v1 + where "non_residue * elem" := (non_residue * elem.c2, elem.c0, elem.c1) + + Enforced with 3 Fp3_mul_gadget's that ensure that: + A.c1 * B.c1 = v1 + A.c0 * B.c0 = v0 + (A.c0+A.c1)*(B.c0+B.c1) = result.c1 + v0 + v1 + + Reference: + "Multiplication and Squaring on Pairing-Friendly Fields" + Devegili, OhEigeartaigh, Scott, Dahab +*/ + v1.reset(new Fp3_variable(pb, FMT(annotation_prefix, " v1"))); + + compute_v1.reset(new Fp3_mul_gadget(pb, A.c1, B.c1, *v1, FMT(annotation_prefix, " compute_v1"))); + + v0_c0.assign(pb, result.c0.c0 - Fp6T::non_residue * v1->c2); + v0_c1.assign(pb, result.c0.c1 - v1->c0); + v0_c2.assign(pb, result.c0.c2 - v1->c1); + v0.reset(new Fp3_variable(pb, v0_c0, v0_c1, v0_c2, FMT(annotation_prefix, " v0"))); + + compute_v0.reset(new Fp3_mul_gadget(pb, A.c0, B.c0, *v0, FMT(annotation_prefix, " compute_v0"))); + + Ac0_plus_Ac1_c0.assign(pb, A.c0.c0 + A.c1.c0); + Ac0_plus_Ac1_c1.assign(pb, A.c0.c1 + A.c1.c1); + Ac0_plus_Ac1_c2.assign(pb, A.c0.c2 + A.c1.c2); + Ac0_plus_Ac1.reset(new Fp3_variable(pb, Ac0_plus_Ac1_c0, Ac0_plus_Ac1_c1, Ac0_plus_Ac1_c2, FMT(annotation_prefix, " Ac0_plus_Ac1"))); + + Bc0_plus_Bc1_c0.assign(pb, B.c0.c0 + B.c1.c0); + Bc0_plus_Bc1_c1.assign(pb, B.c0.c1 + B.c1.c1); + Bc0_plus_Bc1_c2.assign(pb, B.c0.c2 + B.c1.c2); + Bc0_plus_Bc1.reset(new Fp3_variable(pb, Bc0_plus_Bc1_c0, Bc0_plus_Bc1_c1, Bc0_plus_Bc1_c2, FMT(annotation_prefix, " Bc0_plus_Bc1"))); + + result_c1_plus_v0_plus_v1_c0.assign(pb, result.c1.c0 + v0->c0 + v1->c0); + result_c1_plus_v0_plus_v1_c1.assign(pb, result.c1.c1 + v0->c1 + v1->c1); + result_c1_plus_v0_plus_v1_c2.assign(pb, result.c1.c2 + v0->c2 + v1->c2); + result_c1_plus_v0_plus_v1.reset(new Fp3_variable(pb, + result_c1_plus_v0_plus_v1_c0, + result_c1_plus_v0_plus_v1_c1, + result_c1_plus_v0_plus_v1_c2, + FMT(annotation_prefix, " result_c1_plus_v0_plus_v1"))); + + compute_result_c1.reset(new Fp3_mul_gadget(pb, *Ac0_plus_Ac1, *Bc0_plus_Bc1, *result_c1_plus_v0_plus_v1, FMT(annotation_prefix, " compute_result_c1"))); +} + +template +void Fp6_mul_gadget::generate_r1cs_constraints() +{ + compute_v0->generate_r1cs_constraints(); + compute_v1->generate_r1cs_constraints(); + compute_result_c1->generate_r1cs_constraints(); +} + +template +void Fp6_mul_gadget::generate_r1cs_witness() +{ + compute_v0->generate_r1cs_witness(); + compute_v1->generate_r1cs_witness(); + + Ac0_plus_Ac1_c0.evaluate(this->pb); + Ac0_plus_Ac1_c1.evaluate(this->pb); + Ac0_plus_Ac1_c2.evaluate(this->pb); + + Bc0_plus_Bc1_c0.evaluate(this->pb); + Bc0_plus_Bc1_c1.evaluate(this->pb); + Bc0_plus_Bc1_c2.evaluate(this->pb); + + compute_result_c1->generate_r1cs_witness(); + + const Fp6T Aval = A.get_element(); + const Fp6T Bval = B.get_element(); + const Fp6T Rval = Aval * Bval; + + result.generate_r1cs_witness(Rval); + + result_c1_plus_v0_plus_v1_c0.evaluate(this->pb); + result_c1_plus_v0_plus_v1_c1.evaluate(this->pb); + result_c1_plus_v0_plus_v1_c2.evaluate(this->pb); + + compute_result_c1->generate_r1cs_witness(); +} + +template +Fp6_mul_by_2345_gadget::Fp6_mul_by_2345_gadget(protoboard &pb, + const Fp6_variable &A, + const Fp6_variable &B, + const Fp6_variable &result, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), A(A), B(B), result(result) +{ +/* + Karatsuba multiplication for Fp6 as a quadratic extension of Fp3: + v0 = A.c0 * B.c0 + v1 = A.c1 * B.c1 + result.c0 = v0 + non_residue * v1 + result.c1 = (A.c0 + A.c1) * (B.c0 + B.c1) - v0 - v1 + where "non_residue * elem" := (non_residue * elem.c2, elem.c0, elem.c1) + + We know that B.c0.c0 = B.c0.c1 = 0 + + Enforced with 2 Fp3_mul_gadget's that ensure that: + A.c1 * B.c1 = v1 + (A.c0+A.c1)*(B.c0+B.c1) = result.c1 + v0 + v1 + + And one multiplication (three direct constraints) that enforces A.c0 * B.c0 + = v0, where B.c0.c0 = B.c0.c1 = 0. + + Note that (u + v * X + t * X^2) * (0 + 0 * X + z * X^2) = + (v * z * non_residue + t * z * non_residue * X + u * z * X^2) + + Reference: + "Multiplication and Squaring on Pairing-Friendly Fields" + Devegili, OhEigeartaigh, Scott, Dahab +*/ + v1.reset(new Fp3_variable(pb, FMT(annotation_prefix, " v1"))); + compute_v1.reset(new Fp3_mul_gadget(pb, A.c1, B.c1, *v1, FMT(annotation_prefix, " compute_v1"))); + + /* we inline result.c0 in v0 as follows: v0 = (result.c0.c0 - Fp6T::non_residue * v1->c2, result.c0.c1 - v1->c0, result.c0.c2 - v1->c1) */ + v0.reset(new Fp3_variable(pb, FMT(annotation_prefix, " v0"))); + + Ac0_plus_Ac1_c0.assign(pb, A.c0.c0 + A.c1.c0); + Ac0_plus_Ac1_c1.assign(pb, A.c0.c1 + A.c1.c1); + Ac0_plus_Ac1_c2.assign(pb, A.c0.c2 + A.c1.c2); + Ac0_plus_Ac1.reset(new Fp3_variable(pb, Ac0_plus_Ac1_c0, Ac0_plus_Ac1_c1, Ac0_plus_Ac1_c2, FMT(annotation_prefix, " Ac0_plus_Ac1"))); + + Bc0_plus_Bc1_c0.assign(pb, B.c0.c0 + B.c1.c0); + Bc0_plus_Bc1_c1.assign(pb, B.c0.c1 + B.c1.c1); + Bc0_plus_Bc1_c2.assign(pb, B.c0.c2 + B.c1.c2); + Bc0_plus_Bc1.reset(new Fp3_variable(pb, Bc0_plus_Bc1_c0, Bc0_plus_Bc1_c1, Bc0_plus_Bc1_c2, FMT(annotation_prefix, " Bc0_plus_Bc1"))); + + result_c1_plus_v0_plus_v1_c0.assign(pb, result.c1.c0 + v0->c0 + v1->c0); + result_c1_plus_v0_plus_v1_c1.assign(pb, result.c1.c1 + v0->c1 + v1->c1); + result_c1_plus_v0_plus_v1_c2.assign(pb, result.c1.c2 + v0->c2 + v1->c2); + result_c1_plus_v0_plus_v1.reset(new Fp3_variable(pb, + result_c1_plus_v0_plus_v1_c0, + result_c1_plus_v0_plus_v1_c1, + result_c1_plus_v0_plus_v1_c2, + FMT(annotation_prefix, " result_c1_plus_v0_plus_v1"))); + + compute_result_c1.reset(new Fp3_mul_gadget(pb, *Ac0_plus_Ac1, *Bc0_plus_Bc1, *result_c1_plus_v0_plus_v1, FMT(annotation_prefix, " compute_result_c1"))); +} + +template +void Fp6_mul_by_2345_gadget::generate_r1cs_constraints() +{ + compute_v1->generate_r1cs_constraints(); + this->pb.add_r1cs_constraint(r1cs_constraint(A.c0.c1, + Fp3T::non_residue * B.c0.c2, + result.c0.c0 - Fp6T::non_residue * v1->c2), + FMT(this->annotation_prefix, " v0.c0")); + this->pb.add_r1cs_constraint(r1cs_constraint(A.c0.c2, + Fp3T::non_residue * B.c0.c2, + result.c0.c1 - v1->c0), + FMT(this->annotation_prefix, " v0.c1")); + this->pb.add_r1cs_constraint(r1cs_constraint(A.c0.c0, + B.c0.c2, + result.c0.c2 - v1->c1), + FMT(this->annotation_prefix, " v0.c2")); + compute_result_c1->generate_r1cs_constraints(); +} + +template +void Fp6_mul_by_2345_gadget::generate_r1cs_witness() +{ + compute_v1->generate_r1cs_witness(); + + const Fp3T A_c0_val = A.c0.get_element(); + const Fp3T B_c0_val = B.c0.get_element(); + assert(B_c0_val.c0.is_zero()); + assert(B_c0_val.c1.is_zero()); + + const Fp3T v0_val = A_c0_val * B_c0_val; + v0->generate_r1cs_witness(v0_val); + + Ac0_plus_Ac1_c0.evaluate(this->pb); + Ac0_plus_Ac1_c1.evaluate(this->pb); + Ac0_plus_Ac1_c2.evaluate(this->pb); + + Bc0_plus_Bc1_c0.evaluate(this->pb); + Bc0_plus_Bc1_c1.evaluate(this->pb); + Bc0_plus_Bc1_c2.evaluate(this->pb); + + compute_result_c1->generate_r1cs_witness(); + + const Fp6T Aval = A.get_element(); + const Fp6T Bval = B.get_element(); + const Fp6T Rval = Aval * Bval; + + result.generate_r1cs_witness(Rval); + + result_c1_plus_v0_plus_v1_c0.evaluate(this->pb); + result_c1_plus_v0_plus_v1_c1.evaluate(this->pb); + result_c1_plus_v0_plus_v1_c2.evaluate(this->pb); + + compute_result_c1->generate_r1cs_witness(); +} + +template +Fp6_sqr_gadget::Fp6_sqr_gadget(protoboard &pb, + const Fp6_variable &A, + const Fp6_variable &result, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), A(A), result(result) +{ + // We can't do better than 3 Fp3_mul_gadget's for squaring, so we just use multiplication. + mul.reset(new Fp6_mul_gadget(pb, A, A, result, FMT(annotation_prefix, " mul"))); +} + +template +void Fp6_sqr_gadget::generate_r1cs_constraints() +{ + mul->generate_r1cs_constraints(); +} + +template +void Fp6_sqr_gadget::generate_r1cs_witness() +{ + mul->generate_r1cs_witness(); +} + +template +Fp6_cyclotomic_sqr_gadget::Fp6_cyclotomic_sqr_gadget(protoboard &pb, + const Fp6_variable &A, + const Fp6_variable &result, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), A(A), result(result) +{ +/* + my_Fp2 a = my_Fp2(c0.c0, c1.c1); + my_Fp2 b = my_Fp2(c1.c0, c0.c2); + my_Fp2 c = my_Fp2(c0.c1, c1.c2); + + my_Fp2 asq = a.squared(); + my_Fp2 bsq = b.squared(); + my_Fp2 csq = c.squared(); + + result.c0.c0 = 3 * asq_a - 2 * a_a; + result.c1.c1 = 3 * asq_b + 2 * a_b; + + result.c0.c1 = 3 * bsq_a - 2 * c_a; + result.c1.c2 = 3 * bsq_b + 2 * c_b; + + result.c0.c2 = 3 * csq_a - 2 * b_b; + result.c1.c0 = 3 * my_Fp3::non_residue * csq_b + 2 * b_a; + + return Fp6_2over3_model(my_Fp3(A_a, C_a, B_b), + my_Fp3(B_a, A_b, C_b)) +*/ + a.reset(new Fp2_variable(pb, A.c0.c0, A.c1.c1, FMT(annotation_prefix, " a"))); + b.reset(new Fp2_variable(pb, A.c1.c0, A.c0.c2, FMT(annotation_prefix, " b"))); + c.reset(new Fp2_variable(pb, A.c0.c1, A.c1.c2, FMT(annotation_prefix, " c"))); + + asq_c0.assign(pb, (result.c0.c0 + 2 * a->c0) * FieldT(3).inverse()); + asq_c1.assign(pb, (result.c1.c1 - 2 * a->c1) * FieldT(3).inverse()); + + bsq_c0.assign(pb, (result.c0.c1 + 2 * c->c0) * FieldT(3).inverse()); + bsq_c1.assign(pb, (result.c1.c2 - 2 * c->c1) * FieldT(3).inverse()); + + csq_c0.assign(pb, (result.c0.c2 + 2 * b->c1) * FieldT(3).inverse()); + csq_c1.assign(pb, (result.c1.c0 - 2 * b->c0) * (FieldT(3) * Fp2T::non_residue).inverse()); + + asq.reset(new Fp2_variable(pb, asq_c0, asq_c1, FMT(annotation_prefix, " asq"))); + bsq.reset(new Fp2_variable(pb, bsq_c0, bsq_c1, FMT(annotation_prefix, " bsq"))); + csq.reset(new Fp2_variable(pb, csq_c0, csq_c1, FMT(annotation_prefix, " csq"))); + + compute_asq.reset(new Fp2_sqr_gadget(pb, *a, *asq, FMT(annotation_prefix, " compute_asq"))); + compute_bsq.reset(new Fp2_sqr_gadget(pb, *b, *bsq, FMT(annotation_prefix, " compute_bsq"))); + compute_csq.reset(new Fp2_sqr_gadget(pb, *c, *csq, FMT(annotation_prefix, " compute_csq"))); +} + +template +void Fp6_cyclotomic_sqr_gadget::generate_r1cs_constraints() +{ + compute_asq->generate_r1cs_constraints(); + compute_bsq->generate_r1cs_constraints(); + compute_csq->generate_r1cs_constraints(); +} + +template +void Fp6_cyclotomic_sqr_gadget::generate_r1cs_witness() +{ + const Fp6T Aval = A.get_element(); + const Fp6T Rval = Aval.cyclotomic_squared(); + + result.generate_r1cs_witness(Rval); + + asq->evaluate(); + bsq->evaluate(); + csq->evaluate(); + + compute_asq->generate_r1cs_witness(); + compute_bsq->generate_r1cs_witness(); + compute_csq->generate_r1cs_witness(); +} + +} // libsnark + +#endif // FP6_GADGETS_TCC_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/gadget_from_r1cs.hpp b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/gadget_from_r1cs.hpp new file mode 100644 index 0000000..e4b8a2a --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/gadget_from_r1cs.hpp @@ -0,0 +1,45 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for a gadget that can be created from an R1CS constraint system. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef GADGET_FROM_R1CS_HPP_ +#define GADGET_FROM_R1CS_HPP_ + +#include + +#include "gadgetlib1/gadget.hpp" + +namespace libsnark { + +template +class gadget_from_r1cs : public gadget { + +private: + const std::vector > vars; + const r1cs_constraint_system cs; + std::map cs_to_vars; + +public: + + gadget_from_r1cs(protoboard &pb, + const std::vector > &vars, + const r1cs_constraint_system &cs, + const std::string &annotation_prefix); + + void generate_r1cs_constraints(); + void generate_r1cs_witness(const r1cs_primary_input &primary_input, + const r1cs_auxiliary_input &auxiliary_input); +}; + +} // libsnark + +#include "gadgetlib1/gadgets/gadget_from_r1cs.tcc" + +#endif // GADGET_FROM_R1CS_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/gadget_from_r1cs.tcc b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/gadget_from_r1cs.tcc new file mode 100644 index 0000000..bc59b45 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/gadget_from_r1cs.tcc @@ -0,0 +1,123 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for a gadget that can be created from an R1CS constraint system. + + See gadget_from_r1cs.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef GADGET_FROM_R1CS_TCC_ +#define GADGET_FROM_R1CS_TCC_ + +namespace libsnark { + +template +gadget_from_r1cs::gadget_from_r1cs(protoboard &pb, + const std::vector > &vars, + const r1cs_constraint_system &cs, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), + vars(vars), + cs(cs) +{ + cs_to_vars[0] = 0; /* constant term maps to constant term */ + + size_t cs_var_idx = 1; + for (auto va : vars) + { +#ifdef DEBUG + printf("gadget_from_r1cs: translating a block of variables with length %zu\n", va.size()); +#endif + for (auto v : va) + { + cs_to_vars[cs_var_idx] = v.index; + +#ifdef DEBUG + if (v.index != 0) + { + // handle annotations, except for re-annotating constant term + const std::map::const_iterator it = cs.variable_annotations.find(cs_var_idx); + + std::string annotation = FMT(annotation_prefix, " variable_%zu", cs_var_idx); + if (it != cs.variable_annotations.end()) + { + annotation = annotation_prefix + " " + it->second; + } + + pb.augment_variable_annotation(v, annotation); + } +#endif + ++cs_var_idx; + } + } + +#ifdef DEBUG + printf("gadget_from_r1cs: sum of all block lengths: %zu\n", cs_var_idx-1); + printf("gadget_from_r1cs: cs.num_variables(): %zu\n", cs.num_variables()); +#endif + + assert(cs_var_idx - 1 == cs.num_variables()); +} + +template +void gadget_from_r1cs::generate_r1cs_constraints() +{ + for (size_t i = 0; i < cs.num_constraints(); ++i) + { + const r1cs_constraint &constr = cs.constraints[i]; + r1cs_constraint translated_constr; + + for (const linear_term &t: constr.a.terms) + { + translated_constr.a.terms.emplace_back(linear_term(pb_variable(cs_to_vars[t.index]), t.coeff)); + } + + for (const linear_term &t: constr.b.terms) + { + translated_constr.b.terms.emplace_back(linear_term(pb_variable(cs_to_vars[t.index]), t.coeff)); + } + + for (const linear_term &t: constr.c.terms) + { + translated_constr.c.terms.emplace_back(linear_term(pb_variable(cs_to_vars[t.index]), t.coeff)); + } + + std::string annotation = FMT(this->annotation_prefix, " constraint_%zu", i); + +#ifdef DEBUG + auto it = cs.constraint_annotations.find(i); + if (it != cs.constraint_annotations.end()) + { + annotation = this->annotation_prefix + " " + it->second; + } +#endif + this->pb.add_r1cs_constraint(translated_constr, annotation); + } +} + +template +void gadget_from_r1cs::generate_r1cs_witness(const r1cs_primary_input &primary_input, + const r1cs_auxiliary_input &auxiliary_input) +{ + assert(cs.num_inputs() == primary_input.size()); + assert(cs.num_variables() == primary_input.size() + auxiliary_input.size()); + + for (size_t i = 0; i < primary_input.size(); ++i) + { + this->pb.val(pb_variable(cs_to_vars[i+1])) = primary_input[i]; + } + + for (size_t i = 0; i < auxiliary_input.size(); ++i) + { + this->pb.val(pb_variable(cs_to_vars[primary_input.size()+i+1])) = auxiliary_input[i]; + } +} + +} // libsnark + +#endif // GADGET_FROM_R1CS_TCC_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/hashes/crh_gadget.hpp b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/hashes/crh_gadget.hpp new file mode 100644 index 0000000..80338a3 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/hashes/crh_gadget.hpp @@ -0,0 +1,24 @@ +/** + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ +#ifndef CRH_GADGET_HPP_ +#define CRH_GADGET_HPP_ + +#include "gadgetlib1/gadgets/hashes/knapsack/knapsack_gadget.hpp" + +namespace libsnark { + +// for now all CRH gadgets are knapsack CRH's; can be easily extended +// later to more expressive selector types. +template +using CRH_with_field_out_gadget = knapsack_CRH_with_field_out_gadget; + +template +using CRH_with_bit_out_gadget = knapsack_CRH_with_bit_out_gadget; + +} // libsnark + +#endif // CRH_GADGET_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/hashes/digest_selector_gadget.hpp b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/hashes/digest_selector_gadget.hpp new file mode 100644 index 0000000..a7598b9 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/hashes/digest_selector_gadget.hpp @@ -0,0 +1,42 @@ +/** + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ +#ifndef DIGEST_SELECTOR_GADGET_HPP_ +#define DIGEST_SELECTOR_GADGET_HPP_ + +#include + +#include "gadgetlib1/gadgets/basic_gadgets.hpp" +#include "gadgetlib1/gadgets/hashes/hash_io.hpp" + +namespace libsnark { + +template +class digest_selector_gadget : public gadget { +public: + size_t digest_size; + digest_variable input; + pb_linear_combination is_right; + digest_variable left; + digest_variable right; + + digest_selector_gadget(protoboard &pb, + const size_t digest_size, + const digest_variable &input, + const pb_linear_combination &is_right, + const digest_variable &left, + const digest_variable &right, + const std::string &annotation_prefix); + + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +} // libsnark + +#include "gadgetlib1/gadgets/hashes/digest_selector_gadget.tcc" + +#endif // DIGEST_SELECTOR_GADGET_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/hashes/digest_selector_gadget.tcc b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/hashes/digest_selector_gadget.tcc new file mode 100644 index 0000000..422ee17 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/hashes/digest_selector_gadget.tcc @@ -0,0 +1,62 @@ +/** + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ +#ifndef DIGEST_SELECTOR_GADGET_TCC_ +#define DIGEST_SELECTOR_GADGET_TCC_ + +namespace libsnark { + +template +digest_selector_gadget::digest_selector_gadget(protoboard &pb, + const size_t digest_size, + const digest_variable &input, + const pb_linear_combination &is_right, + const digest_variable &left, + const digest_variable &right, + const std::string &annotation_prefix) : +gadget(pb, annotation_prefix), digest_size(digest_size), input(input), is_right(is_right), left(left), right(right) +{ +} + +template +void digest_selector_gadget::generate_r1cs_constraints() +{ + for (size_t i = 0; i < digest_size; ++i) + { + /* + input = is_right * right + (1-is_right) * left + input - left = is_right(right - left) + */ + this->pb.add_r1cs_constraint(r1cs_constraint(is_right, right.bits[i] - left.bits[i], input.bits[i] - left.bits[i]), + FMT(this->annotation_prefix, " propagate_%zu", i)); + } +} + +template +void digest_selector_gadget::generate_r1cs_witness() +{ + is_right.evaluate(this->pb); + + assert(this->pb.lc_val(is_right) == FieldT::one() || this->pb.lc_val(is_right) == FieldT::zero()); + if (this->pb.lc_val(is_right) == FieldT::one()) + { + for (size_t i = 0; i < digest_size; ++i) + { + this->pb.val(right.bits[i]) = this->pb.val(input.bits[i]); + } + } + else + { + for (size_t i = 0; i < digest_size; ++i) + { + this->pb.val(left.bits[i]) = this->pb.val(input.bits[i]); + } + } +} + +} // libsnark + +#endif // DIGEST_SELECTOR_GADGET_TCC_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/hashes/hash_io.hpp b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/hashes/hash_io.hpp new file mode 100644 index 0000000..80ca19c --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/hashes/hash_io.hpp @@ -0,0 +1,63 @@ +/** + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ +#ifndef HASH_IO_HPP_ +#define HASH_IO_HPP_ +#include +#include +#include "gadgetlib1/gadgets/basic_gadgets.hpp" + +namespace libsnark { + +template +class digest_variable : public gadget { +public: + size_t digest_size; + pb_variable_array bits; + + digest_variable(protoboard &pb, + const size_t digest_size, + const std::string &annotation_prefix); + + digest_variable(protoboard &pb, + const size_t digest_size, + const pb_variable_array &partial_bits, + const pb_variable &padding, + const std::string &annotation_prefix); + + void generate_r1cs_constraints(); + void generate_r1cs_witness(const bit_vector& contents); + bit_vector get_digest() const; +}; + +template +class block_variable : public gadget { +public: + size_t block_size; + pb_variable_array bits; + + block_variable(protoboard &pb, + const size_t block_size, + const std::string &annotation_prefix); + + block_variable(protoboard &pb, + const std::vector > &parts, + const std::string &annotation_prefix); + + block_variable(protoboard &pb, + const digest_variable &left, + const digest_variable &right, + const std::string &annotation_prefix); + + void generate_r1cs_constraints(); + void generate_r1cs_witness(const bit_vector& contents); + bit_vector get_block() const; +}; + +} // libsnark +#include "gadgetlib1/gadgets/hashes/hash_io.tcc" + +#endif // HASH_IO_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/hashes/hash_io.tcc b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/hashes/hash_io.tcc new file mode 100644 index 0000000..b122d8f --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/hashes/hash_io.tcc @@ -0,0 +1,105 @@ +/** + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ +#ifndef HASH_IO_TCC_ +#define HASH_IO_TCC_ + +namespace libsnark { + +template +digest_variable::digest_variable(protoboard &pb, + const size_t digest_size, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), digest_size(digest_size) +{ + bits.allocate(pb, digest_size, FMT(this->annotation_prefix, " bits")); +} + +template +digest_variable::digest_variable(protoboard &pb, + const size_t digest_size, + const pb_variable_array &partial_bits, + const pb_variable &padding, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), digest_size(digest_size) +{ + assert(bits.size() <= digest_size); + bits = partial_bits; + while (bits.size() != digest_size) + { + bits.emplace_back(padding); + } +} + +template +void digest_variable::generate_r1cs_constraints() +{ + for (size_t i = 0; i < digest_size; ++i) + { + generate_boolean_r1cs_constraint(this->pb, bits[i], FMT(this->annotation_prefix, " bits_%zu", i)); + } +} + +template +void digest_variable::generate_r1cs_witness(const bit_vector& contents) +{ + bits.fill_with_bits(this->pb, contents); +} + +template +bit_vector digest_variable::get_digest() const +{ + return bits.get_bits(this->pb); +} + +template +block_variable::block_variable(protoboard &pb, + const size_t block_size, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), block_size(block_size) +{ + bits.allocate(pb, block_size, FMT(this->annotation_prefix, " bits")); +} + +template +block_variable::block_variable(protoboard &pb, + const std::vector > &parts, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix) +{ + for (auto &part : parts) + { + bits.insert(bits.end(), part.begin(), part.end()); + } +} + +template +block_variable::block_variable(protoboard &pb, + const digest_variable &left, + const digest_variable &right, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix) +{ + assert(left.bits.size() == right.bits.size()); + block_size = 2 * left.bits.size(); + bits.insert(bits.end(), left.bits.begin(), left.bits.end()); + bits.insert(bits.end(), right.bits.begin(), right.bits.end()); +} + +template +void block_variable::generate_r1cs_witness(const bit_vector& contents) +{ + bits.fill_with_bits(this->pb, contents); +} + +template +bit_vector block_variable::get_block() const +{ + return bits.get_bits(this->pb); +} + +} // libsnark +#endif // HASH_IO_TCC_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/hashes/knapsack/knapsack_gadget.hpp b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/hashes/knapsack/knapsack_gadget.hpp new file mode 100644 index 0000000..571a498 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/hashes/knapsack/knapsack_gadget.hpp @@ -0,0 +1,134 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for the knapsack gadget. + + The gadget checks the correct execution of a knapsack (modular subset-sum) over + the field specified in the template parameter. With suitable choices of parameters + such knapsacks are collision-resistant hashes (CRHs). See \[Ajt96] and \[GGH96]. + + Given two positive integers m (the input length) and d (the dimension), + and a matrix M over the field F and of dimension dxm, the hash H_M maps {0,1}^m + to F^d by sending x to M*x. Security of the function (very roughly) depends on + d*log(|F|). + + Below, we give two different gadgets: + - knapsack_CRH_with_field_out_gadget, which verifies H_M + - knapsack_CRH_with_bit_out_gadget, which verifies H_M when its output is "expanded" to bits. + In both cases, a method ("sample_randomness") allows to sample M. + + The parameter d (the dimension) is fixed at compile time in the struct + knapsack_dimension below. The parameter m (the input lenght) can be chosen + at run time (in either gadget). + + + References: + + \[Ajt96]: + "Generating hard instances of lattice problems", + Miklos Ajtai, + STOC 1996 + + \[GGH96]: + "Collision-free hashing from lattice problems", + Oded Goldreich, Shafi Goldwasser, Shai Halevi, + ECCC TR95-042 + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef KNAPSACK_GADGET_HPP_ +#define KNAPSACK_GADGET_HPP_ + +#include "gadgetlib1/gadgets/basic_gadgets.hpp" +#include "gadgetlib1/gadgets/hashes/hash_io.hpp" +#include "common/data_structures/merkle_tree.hpp" + +namespace libsnark { + +/************************** Choice of dimension ******************************/ + +template +struct knapsack_dimension { + // the size of FieldT should be (approximately) at least 200 bits + static const size_t dimension = 1; +}; + +/*********************** Knapsack with field output **************************/ + +template +class knapsack_CRH_with_field_out_gadget : public gadget { +private: + static std::vector knapsack_coefficients; + static size_t num_cached_coefficients; + +public: + size_t input_len; + size_t dimension; + + block_variable input_block; + pb_linear_combination_array output; + + knapsack_CRH_with_field_out_gadget(protoboard &pb, + const size_t input_len, + const block_variable &input_block, + const pb_linear_combination_array &output, + const std::string &annotation_prefix); + void generate_r1cs_constraints(); + void generate_r1cs_witness(); + + static size_t get_digest_len(); + static size_t get_block_len(); /* return 0 as block length, as the hash function is variable-input */ + static std::vector get_hash(const bit_vector &input); + static void sample_randomness(const size_t input_len); + + /* for debugging */ + static size_t expected_constraints(); +}; + +/********************** Knapsack with binary output **************************/ + +template +class knapsack_CRH_with_bit_out_gadget : public gadget { +public: + typedef bit_vector hash_value_type; + typedef merkle_authentication_path merkle_authentication_path_type; + + size_t input_len; + size_t dimension; + + pb_linear_combination_array output; + + std::shared_ptr > hasher; + + block_variable input_block; + digest_variable output_digest; + + knapsack_CRH_with_bit_out_gadget(protoboard &pb, + const size_t input_len, + const block_variable &input_block, + const digest_variable &output_digest, + const std::string &annotation_prefix); + void generate_r1cs_constraints(const bool enforce_bitness=true); + void generate_r1cs_witness(); + + static size_t get_digest_len(); + static size_t get_block_len(); /* return 0 as block length, as the hash function is variable-input */ + static hash_value_type get_hash(const bit_vector &input); + static void sample_randomness(const size_t input_len); + + /* for debugging */ + static size_t expected_constraints(const bool enforce_bitness=true); +}; + +template +void test_knapsack_CRH_with_bit_out_gadget(); + +} // libsnark + +#include "gadgetlib1/gadgets/hashes/knapsack/knapsack_gadget.tcc" + +#endif // KNAPSACK_GADGET_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/hashes/knapsack/knapsack_gadget.tcc b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/hashes/knapsack/knapsack_gadget.tcc new file mode 100644 index 0000000..ca3b5aa --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/hashes/knapsack/knapsack_gadget.tcc @@ -0,0 +1,259 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for the knapsack gadget. + + See knapsack_gadget.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef KNAPSACK_GADGET_TCC_ +#define KNAPSACK_GADGET_TCC_ + +#include "algebra/fields/field_utils.hpp" +#include "common/rng.hpp" + +namespace libsnark { + +template +std::vector knapsack_CRH_with_field_out_gadget::knapsack_coefficients; +template +size_t knapsack_CRH_with_field_out_gadget::num_cached_coefficients; + +template +knapsack_CRH_with_field_out_gadget::knapsack_CRH_with_field_out_gadget(protoboard &pb, + const size_t input_len, + const block_variable &input_block, + const pb_linear_combination_array &output, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), + input_len(input_len), + dimension(knapsack_dimension::dimension), + input_block(input_block), + output(output) +{ + assert(input_block.bits.size() == input_len); + if (num_cached_coefficients < dimension * input_len) + { + sample_randomness(input_len); + } + assert(output.size() == this->get_digest_len()); +} + +template +void knapsack_CRH_with_field_out_gadget::generate_r1cs_constraints() +{ + for (size_t i = 0; i < dimension; ++i) + { + this->pb.add_r1cs_constraint(r1cs_constraint(1, + pb_coeff_sum(input_block.bits, + std::vector(knapsack_coefficients.begin() + input_len * i, + knapsack_coefficients.begin() + input_len * (i+1))), + output[i]), FMT(this->annotation_prefix, " knapsack_%zu", i)); + } +} + +template +void knapsack_CRH_with_field_out_gadget::generate_r1cs_witness() +{ + const bit_vector input = input_block.get_block(); + + for (size_t i = 0; i < dimension; ++i) + { + FieldT sum = FieldT::zero(); + for (size_t k = 0; k < input_len; ++k) + { + if (input[k]) + { + sum += knapsack_coefficients[input_len*i + k]; + } + } + + this->pb.lc_val(output[i]) = sum; + } +} + +template +size_t knapsack_CRH_with_field_out_gadget::get_digest_len() +{ + return knapsack_dimension::dimension; +} + +template +size_t knapsack_CRH_with_field_out_gadget::get_block_len() +{ + return 0; +} + +template +std::vector knapsack_CRH_with_field_out_gadget::get_hash(const bit_vector &input) +{ + const size_t dimension = knapsack_dimension::dimension; + if (num_cached_coefficients < dimension * input.size()) + { + sample_randomness(input.size()); + } + + std::vector result(dimension, FieldT::zero()); + + for (size_t i = 0; i < dimension; ++i) + { + for (size_t k = 0; k < input.size(); ++k) + { + if (input[k]) + { + result[i] += knapsack_coefficients[input.size()*i + k]; + } + } + } + + return result; +} + +template +size_t knapsack_CRH_with_field_out_gadget::expected_constraints() +{ + return knapsack_dimension::dimension; +} + +template +void knapsack_CRH_with_field_out_gadget::sample_randomness(const size_t input_len) +{ + const size_t num_coefficients = knapsack_dimension::dimension * input_len; + if (num_coefficients > num_cached_coefficients) + { + knapsack_coefficients.resize(num_coefficients); + for (size_t i = num_cached_coefficients; i < num_coefficients; ++i) + { + knapsack_coefficients[i] = SHA512_rng(i); + } + num_cached_coefficients = num_coefficients; + } +} + +template +knapsack_CRH_with_bit_out_gadget::knapsack_CRH_with_bit_out_gadget(protoboard &pb, + const size_t input_len, + const block_variable &input_block, + const digest_variable &output_digest, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), + input_len(input_len), + dimension(knapsack_dimension::dimension), + input_block(input_block), + output_digest(output_digest) +{ + assert(output_digest.bits.size() == this->get_digest_len()); + + output.resize(dimension); + + for (size_t i = 0; i < dimension; ++i) + { + output[i].assign(pb, pb_packing_sum(pb_variable_array(output_digest.bits.begin() + i * FieldT::size_in_bits(), + output_digest.bits.begin() + (i + 1) * FieldT::size_in_bits()))); + } + + hasher.reset(new knapsack_CRH_with_field_out_gadget(pb, input_len, input_block, output, FMT(annotation_prefix, " hasher"))); +} + + +template +void knapsack_CRH_with_bit_out_gadget::generate_r1cs_constraints(const bool enforce_bitness) +{ + hasher->generate_r1cs_constraints(); + + if (enforce_bitness) + { + for (size_t k = 0; k < output_digest.bits.size(); ++k) + { + generate_boolean_r1cs_constraint(this->pb, output_digest.bits[k], FMT(this->annotation_prefix, " output_digest_%zu", k)); + } + } +} + +template +void knapsack_CRH_with_bit_out_gadget::generate_r1cs_witness() +{ + hasher->generate_r1cs_witness(); + + /* do unpacking in place */ + const bit_vector input = input_block.bits.get_bits(this->pb); + for (size_t i = 0; i < dimension; ++i) + { + pb_variable_array va(output_digest.bits.begin() + i * FieldT::size_in_bits(), + output_digest.bits.begin() + (i + 1) * FieldT::size_in_bits()); + va.fill_with_bits_of_field_element(this->pb, this->pb.lc_val(output[i])); + } +} + +template +size_t knapsack_CRH_with_bit_out_gadget::get_digest_len() +{ + return knapsack_dimension::dimension * FieldT::size_in_bits(); +} + +template +size_t knapsack_CRH_with_bit_out_gadget::get_block_len() +{ + return 0; +} + +template +bit_vector knapsack_CRH_with_bit_out_gadget::get_hash(const bit_vector &input) +{ + const std::vector hash_elems = knapsack_CRH_with_field_out_gadget::get_hash(input); + hash_value_type result; + + for (const FieldT &elt : hash_elems) + { + bit_vector elt_bits = convert_field_element_to_bit_vector(elt); + result.insert(result.end(), elt_bits.begin(), elt_bits.end()); + } + + return result; +} + +template +size_t knapsack_CRH_with_bit_out_gadget::expected_constraints(const bool enforce_bitness) +{ + const size_t hasher_constraints = knapsack_CRH_with_field_out_gadget::expected_constraints(); + const size_t bitness_constraints = (enforce_bitness ? get_digest_len() : 0); + return hasher_constraints + bitness_constraints; +} + +template +void knapsack_CRH_with_bit_out_gadget::sample_randomness(const size_t input_len) +{ + knapsack_CRH_with_field_out_gadget::sample_randomness(input_len); +} + +template +void test_knapsack_CRH_with_bit_out_gadget_internal(const size_t dimension, const bit_vector &input_bits, const bit_vector &digest_bits) +{ + assert(knapsack_dimension::dimension == dimension); + knapsack_CRH_with_bit_out_gadget::sample_randomness(input_bits.size()); + protoboard pb; + + block_variable input_block(pb, input_bits.size(), "input_block"); + digest_variable output_digest(pb, knapsack_CRH_with_bit_out_gadget::get_digest_len(), "output_digest"); + knapsack_CRH_with_bit_out_gadget H(pb, input_bits.size(), input_block, output_digest, "H"); + + input_block.generate_r1cs_witness(input_bits); + H.generate_r1cs_constraints(); + H.generate_r1cs_witness(); + + assert(output_digest.get_digest().size() == digest_bits.size()); + assert(pb.is_satisfied()); + + const size_t num_constraints = pb.num_constraints(); + const size_t expected_constraints = knapsack_CRH_with_bit_out_gadget::expected_constraints(); + assert(num_constraints == expected_constraints); +} + +} // libsnark + +#endif // KNAPSACK_GADGET_TCC_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/hashes/knapsack/tests/generate_knapsack_tests.py b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/hashes/knapsack/tests/generate_knapsack_tests.py new file mode 100644 index 0000000..fb16de2 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/hashes/knapsack/tests/generate_knapsack_tests.py @@ -0,0 +1,76 @@ +#!/usr/bin/env python +## +# @author This file is part of libsnark, developed by SCIPR Lab +# and contributors (see AUTHORS). +# @copyright MIT license (see LICENSE file) + +import random +import hashlib +import struct +import math + +def bitlength(p): + return int(math.ceil(math.log(p, 2))) + +def SHA512_prng(i, p): + """Generates nothing-up-my-sleeve random numbers. i-th random number + is obtained by applying SHA512 to successively (i || 0), (i || 1), + ... (both i and the counter treated as 64-bit integers) until the + first of them, when having all but ceil(log(p)) bits cleared, is + less than p. + + TODO: describe byte order + + """ + mask = 2 ** bitlength(p) + it = 0 + while True: + val = int(hashlib.sha512(struct.pack("=QQ", i, it)).digest()[::-1].encode('hex'), 16) % mask + if val < p: + return val + else: + it += 1 + +def int_to_bits(i, p): + outbits = bin(i)[2:][::-1] + outbits = outbits + '0' * (bitlength(p) - len(outbits)) + return [int(b) for b in outbits] + +def bool_arr(bits): + return '{%s}' % ','.join(str(b) for b in bits) + +def knapsack_hash(bits, p, dimension): + result = [] + for chunk in xrange(dimension): + total = 0 + for i, b in enumerate(bits): + total = (total + b * SHA512_prng(chunk * len(bits) + i, p)) % p + print '// hash_vector[%d] = %d' % (chunk, total) + result += int_to_bits(total, p) + return result + +def generate_knapsack_test(p_name, dimension, bits): + print "// tests for knapsack_CRH_with_bit_output<%s> and dimension %d" % (p_name, dimension) + p = globals()[p_name] + print 'const size_t dimension = %d;' % dimension + print 'const bit_vector input_bits = %s;' % bool_arr(bits) + h = knapsack_hash(bits, p, dimension) + print 'const bit_vector digest_bits = %s;' % bool_arr(h) + +def rand_bits(count): + return [random.randint(0, 1) for i in xrange(count)] + +bn128_r = 21888242871839275222246405745257275088548364400416034343698204186575808495617 +edwards_r = 1552511030102430251236801561344621993261920897571225601 +mnt4_r = 475922286169261325753349249653048451545124878552823515553267735739164647307408490559963137 +mnt6_r = 475922286169261325753349249653048451545124879242694725395555128576210262817955800483758081 + +if __name__ == '__main__': + random.seed(0) # for reproducibility + + contents = rand_bits(10) + for dimension in [1,3]: + generate_knapsack_test("bn128_r", dimension, contents) + generate_knapsack_test("edwards_r", dimension, contents) + generate_knapsack_test("mnt4_r", dimension, contents) + generate_knapsack_test("mnt6_r", dimension, contents) diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/hashes/knapsack/tests/test_knapsack_gadget.cpp b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/hashes/knapsack/tests/test_knapsack_gadget.cpp new file mode 100644 index 0000000..54a7119 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/hashes/knapsack/tests/test_knapsack_gadget.cpp @@ -0,0 +1,156 @@ +/** + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifdef CURVE_BN128 +#include "algebra/curves/bn128/bn128_pp.hpp" +#endif +#include "algebra/curves/edwards/edwards_pp.hpp" +#include "algebra/curves/mnt/mnt4/mnt4_pp.hpp" +#include "algebra/curves/mnt/mnt6/mnt6_pp.hpp" +#include "gadgetlib1/gadgets/hashes/knapsack/knapsack_gadget.hpp" + +namespace libsnark { + +/* These are fully specialized so cannot live in the corresponding + * .tcc file. Furthermore, the tests are autogenerated (see + * generate_knapsack_tests.py) and contain hard-to-read constants. */ + +#ifdef CURVE_BN128 // BN128 has fancy dependencies so it may be disabled +template<> +void test_knapsack_CRH_with_bit_out_gadget >() +{ + typedef Fr FieldT; + const size_t dimension = knapsack_dimension::dimension; + const bit_vector input_bits = {1,1,0,0,1,0,1,0,0,1}; + bit_vector digest_bits; + + if (dimension == 1) + { + // hash_vector[0] = 19358128397917746746715486768528331499472172224025066869640626465460783114989 + digest_bits = {1,0,1,1,0,1,1,1,0,1,0,1,0,1,1,0,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,0,0,1,1,1,0,1,0,0,0,1,0,1,0,1,0,0,1,0,0,0,1,0,1,0,1,1,0,0,1,1,0,0,1,0,0,1,1,0,0,1,1,1,0,1,1,1,0,0,1,0,1,1,0,0,1,1,1,1,0,1,0,1,1,0,0,1,1,1,0,0,1,0,1,0,1,1,0,0,1,1,0,0,0,0,1,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,0,0,0,1,0,1,1,1,0,1,1,1,1,0,0,1,1,0,0,1,0,0,1,0,0,1,1,0,0,0,1,0,0,0,0,1,0,1,0,1,0,0,0,0,1,0,0,0,0,0,1,1,0,1,0,0,0,1,0,0,1,1,1,1,0,0,0,0,1,0,1,1,0,1,1,0,1,0,0,0,1,1,0,0,0,1,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,0,0,1,0,0,0,1,1,0,0,1,1,0,1,0,1,0,1}; + } + else if (dimension == 3) + { + // hash_vector[0] = 19358128397917746746715486768528331499472172224025066869640626465460783114989 + // hash_vector[1] = 14647747576997998233659818696206913383172548767133711974605617840575181365754 + // hash_vector[2] = 2920097934141708417756781671323464432263982766704831772622221878471527707999 + digest_bits = {1,0,1,1,0,1,1,1,0,1,0,1,0,1,1,0,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,0,0,1,1,1,0,1,0,0,0,1,0,1,0,1,0,0,1,0,0,0,1,0,1,0,1,1,0,0,1,1,0,0,1,0,0,1,1,0,0,1,1,1,0,1,1,1,0,0,1,0,1,1,0,0,1,1,1,1,0,1,0,1,1,0,0,1,1,1,0,0,1,0,1,0,1,1,0,0,1,1,0,0,0,0,1,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,0,0,0,1,0,1,1,1,0,1,1,1,1,0,0,1,1,0,0,1,0,0,1,0,0,1,1,0,0,0,1,0,0,0,0,1,0,1,0,1,0,0,0,0,1,0,0,0,0,0,1,1,0,1,0,0,0,1,0,0,1,1,1,1,0,0,0,0,1,0,1,1,0,1,1,0,1,0,0,0,1,1,0,0,0,1,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,0,0,1,0,0,0,1,1,0,0,1,1,0,1,0,1,0,1,0,1,0,1,1,1,1,1,1,0,0,0,0,1,0,0,0,1,1,0,1,0,0,1,0,1,1,0,1,0,1,1,0,1,1,1,1,1,0,0,0,1,1,0,1,0,0,1,1,0,1,0,0,0,0,0,1,0,0,0,0,0,0,1,1,0,1,0,1,1,1,0,0,0,1,0,1,1,0,1,1,1,0,1,0,1,0,0,0,1,1,1,0,1,0,0,1,0,0,1,1,1,0,1,1,0,1,0,1,0,0,1,1,1,0,1,0,0,1,1,1,0,1,0,0,0,0,1,0,0,0,1,1,1,1,0,0,1,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,1,1,0,1,1,0,1,0,0,0,0,1,1,1,0,1,0,0,0,1,1,0,1,1,1,0,0,1,0,1,0,0,1,0,1,0,1,1,1,0,0,0,0,1,0,1,0,0,1,1,0,0,1,1,0,0,0,1,1,0,1,0,0,0,0,0,0,1,0,0,0,0,1,0,0,1,0,1,1,0,0,1,0,1,0,1,0,0,1,0,0,0,1,1,0,0,0,0,0,0,1,1,1,1,1,1,0,1,0,1,0,1,0,1,1,0,0,1,1,1,1,0,1,0,0,1,0,1,0,0,0,0,1,0,1,0,0,1,0,0,0,0,1,0,0,1,1,0,1,1,0,1,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,0,0,0,1,1,1,0,1,0,1,1,1,1,1,0,1,0,1,1,0,0,0,1,1,0,1,0,0,0,0,1,0,1,0,1,0,0,1,0,0,1,0,1,1,0,0,1,0,1,0,0,0,1,0,0,1,1,0,0,1,1,1,1,0,1,1,0,1,0,1,1,0,0,0,1,1,1,0,1,1,1,1,0,1,0,0,0,0,0,0,0,0,1,1,0,0,1,1,0,1,1,1,1,1,1,0,1,1,0,0,0,1,0,1,1,1,1,0,1,1,0,1,1,0,1,1,0,1,0,0,1,1,1,1,0,0,1,0,1,0,1,0,1,0,1,0,0,1,1,1,1,0,1,1,0,1,0,0,0,0,1,0,0,0,0,1,1,1,1,0,1,1,0,1,0,0,1,0,1,1,1,0,0,1,1,0,0,0}; + } + else + { + printf("unsupported dimension\n"); + return; + } + + test_knapsack_CRH_with_bit_out_gadget_internal(dimension, input_bits, digest_bits); +} +#endif + +template<> +void test_knapsack_CRH_with_bit_out_gadget >() +{ + typedef Fr FieldT; + const size_t dimension = knapsack_dimension::dimension; + const bit_vector input_bits = {1,1,0,0,1,0,1,0,0,1}; + bit_vector digest_bits; + + if (dimension == 1) + { + // hash_vector[0] = 212682788919191185746369136465846038795231156077120478 + digest_bits = {0,1,1,1,1,0,1,1,1,1,0,1,0,0,1,1,0,0,1,0,0,1,1,1,0,1,0,1,0,1,1,0,1,0,1,1,0,1,1,1,0,1,0,1,0,1,0,1,0,1,1,0,1,0,0,1,1,0,1,0,1,0,0,1,1,0,1,1,1,1,1,1,1,0,1,0,1,1,0,0,0,0,1,0,0,1,1,1,0,0,1,0,1,0,0,0,0,1,1,1,1,1,1,0,1,0,0,1,1,1,0,1,0,0,0,0,0,1,1,0,1,0,1,1,1,0,0,1,1,1,1,0,0,1,1,0,0,1,1,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,1,1,1,1,0,1,1,0,0,1,1,1,0,0,0,0,1,1,1,0,0,0,1,0,0,0}; + } + else if (dimension == 3) + { + // hash_vector[0] = 212682788919191185746369136465846038795231156077120478 + // hash_vector[1] = 208444103178970253386051017880119245406612361624666932 + // hash_vector[2] = 753512267902403701181906991398452949644481965281690464 + digest_bits = {0,1,1,1,1,0,1,1,1,1,0,1,0,0,1,1,0,0,1,0,0,1,1,1,0,1,0,1,0,1,1,0,1,0,1,1,0,1,1,1,0,1,0,1,0,1,0,1,0,1,1,0,1,0,0,1,1,0,1,0,1,0,0,1,1,0,1,1,1,1,1,1,1,0,1,0,1,1,0,0,0,0,1,0,0,1,1,1,0,0,1,0,1,0,0,0,0,1,1,1,1,1,1,0,1,0,0,1,1,1,0,1,0,0,0,0,0,1,1,0,1,0,1,1,1,0,0,1,1,1,1,0,0,1,1,0,0,1,1,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,1,1,1,1,0,1,1,0,0,1,1,1,0,0,0,0,1,1,1,0,0,0,1,0,0,0,0,0,1,0,1,1,0,0,1,1,0,0,0,0,1,1,1,1,1,1,1,1,1,1,0,1,1,0,0,1,0,0,1,1,1,0,0,1,0,0,0,0,0,0,1,1,0,1,1,1,0,0,0,1,1,0,0,0,0,0,1,1,0,1,0,0,1,0,1,0,0,0,0,1,1,0,1,1,1,0,1,1,0,1,1,0,0,1,1,0,0,1,1,0,1,1,1,0,1,0,0,0,1,1,1,1,0,1,0,0,0,0,1,1,0,0,1,1,1,0,0,1,0,0,0,1,1,1,1,1,1,0,0,0,0,0,1,0,1,0,1,0,1,1,1,0,1,0,1,1,0,0,0,1,1,1,1,1,0,0,1,1,1,1,1,0,0,0,1,0,1,1,0,1,0,0,0,1,0,0,0,0,0,0,0,0,1,1,0,1,1,0,0,0,0,1,1,0,1,1,0,1,1,1,1,0,1,0,1,0,0,1,0,0,1,1,0,0,1,1,1,0,1,1,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,1,0,1,1,1,1,0,1,1,0,1,0,1,0,1,1,0,1,0,0,1,0,0,0,0,0,0,1,1,1,0,1,0,0,1,1,0,0,0,0,1,0,0,0,1,1,0,0,1,1,0,0,1,0,0,0,0,1,1,0,1,0,0,0,1,0,0,0,0,1,1,1,0,0,1,1,1,0,0,0,1,0,0,1,1,1,0,1,1,1,1,1,1,1,0,0,0,0,0,0,0,1,1,0,1,1,1,1,1,0,1,1,1,0,1,1,1,1,1,0,0}; + } + else + { + printf("unsupported dimension\n"); + return; + } + + test_knapsack_CRH_with_bit_out_gadget_internal(dimension, input_bits, digest_bits); +} + +template<> +void test_knapsack_CRH_with_bit_out_gadget >() +{ + typedef Fr FieldT; + const size_t dimension = knapsack_dimension::dimension; + const bit_vector input_bits = {1,1,0,0,1,0,1,0,0,1}; + bit_vector digest_bits; + + if (dimension == 1) + { + // hash_vector[0] = 5849873898117023322885358421738220900336336792093854367505800858141298949423761399689551 + digest_bits = {1,1,1,1,0,0,1,0,1,0,0,0,1,1,0,0,1,1,0,0,1,0,0,0,0,1,0,1,0,0,1,1,0,1,1,1,0,0,0,0,0,0,0,0,0,0,1,0,1,0,1,1,0,1,1,1,0,1,1,0,1,1,1,0,1,0,1,1,0,1,0,1,0,1,1,1,0,1,0,1,1,0,0,1,1,0,0,1,0,1,0,1,0,0,1,0,1,0,0,0,0,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1,1,0,1,1,1,0,0,0,0,0,1,1,0,0,0,1,1,1,1,0,1,0,1,0,1,1,0,1,0,0,1,0,0,0,1,1,1,1,1,1,1,1,0,1,0,1,0,0,0,0,0,1,1,1,1,0,0,0,1,0,0,1,1,1,0,0,0,1,1,1,1,1,1,0,1,0,1,0,0,1,1,0,0,1,1,1,1,0,0,0,1,0,0,0,0,1,0,1,0,1,0,0,1,0,0,1,1,0,1,1,1,1,0,0,1,1,0,0,1,1,0,1,0,1,1,0,1,1,1,0,0,1,1,1,1,1,0,1,0,0,0,1,0,0,1,1,1,0,1,1,0,1,1,0,0,1,1,0,0,0,0,0,1,0,1,1,0,0,0,0,1,1,1,1,0,1,0,0,0,0,0,0}; + } + else if (dimension == 3) + { + // hash_vector[0] = 5849873898117023322885358421738220900336336792093854367505800858141298949423761399689551 + // hash_vector[1] = 53446030978469113922159049491079907226345855403292835149508287198951741313094713251809734 + // hash_vector[2] = 40260485387428589838404886401807432179330886729322245141417568340931755675196614173996382 +digest_bits = {1,1,1,1,0,0,1,0,1,0,0,0,1,1,0,0,1,1,0,0,1,0,0,0,0,1,0,1,0,0,1,1,0,1,1,1,0,0,0,0,0,0,0,0,0,0,1,0,1,0,1,1,0,1,1,1,0,1,1,0,1,1,1,0,1,0,1,1,0,1,0,1,0,1,1,1,0,1,0,1,1,0,0,1,1,0,0,1,0,1,0,1,0,0,1,0,1,0,0,0,0,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1,1,0,1,1,1,0,0,0,0,0,1,1,0,0,0,1,1,1,1,0,1,0,1,0,1,1,0,1,0,0,1,0,0,0,1,1,1,1,1,1,1,1,0,1,0,1,0,0,0,0,0,1,1,1,1,0,0,0,1,0,0,1,1,1,0,0,0,1,1,1,1,1,1,0,1,0,1,0,0,1,1,0,0,1,1,1,1,0,0,0,1,0,0,0,0,1,0,1,0,1,0,0,1,0,0,1,1,0,1,1,1,1,0,0,1,1,0,0,1,1,0,1,0,1,1,0,1,1,1,0,0,1,1,1,1,1,0,1,0,0,0,1,0,0,1,1,1,0,1,1,0,1,1,0,0,1,1,0,0,0,0,0,1,0,1,1,0,0,0,0,1,1,1,1,0,1,0,0,0,0,0,0,0,1,1,0,0,0,1,1,1,0,0,1,0,0,1,0,1,0,0,0,0,0,1,0,1,1,0,0,0,0,1,1,0,0,0,1,1,1,1,1,0,1,0,1,1,0,1,1,1,1,1,1,0,0,1,0,1,0,0,1,0,0,1,0,1,1,1,1,1,1,1,1,0,1,1,0,0,0,1,1,0,1,1,1,1,1,1,1,1,0,1,1,1,0,1,0,1,1,0,1,0,1,0,0,0,1,0,0,0,1,0,0,1,1,1,0,1,0,0,0,0,1,1,1,1,1,0,1,1,0,1,1,1,0,0,1,0,1,1,1,0,0,0,0,1,1,0,0,1,1,0,0,0,1,1,1,1,1,0,0,1,0,1,1,0,0,1,0,0,1,0,1,0,1,1,0,1,1,0,1,0,1,0,0,0,0,0,1,0,1,1,0,1,0,1,0,0,0,1,1,1,0,1,1,0,0,1,0,1,0,0,1,1,0,1,1,0,0,0,1,0,0,0,0,0,1,1,1,1,1,1,0,1,1,0,0,0,1,1,1,0,0,0,1,0,0,1,1,1,1,0,1,1,0,1,1,0,1,0,0,0,1,0,0,1,0,0,1,1,1,1,1,0,1,1,0,0,1,0,1,1,1,1,0,1,1,1,0,1,1,0,1,0,1,1,0,0,0,0,1,1,1,1,0,1,0,1,0,1,0,1,1,0,0,1,1,1,1,0,1,0,0,1,0,1,0,0,1,1,0,0,1,1,1,0,0,1,0,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,0,1,0,0,1,0,1,0,1,1,0,1,0,0,0,1,1,1,0,1,1,0,0,1,1,0,1,0,1,1,1,0,1,1,1,0,0,0,1,0,1,1,1,1,0,0,0,0,1,0,0,0,0,1,0,0,1,0,0,0,1,0,1,1,0,0,1,0,0,0,1,0,1,0,0,1,0,1,0,1,1,0,1,1,1,0,1,0,1,0,1,0,1,0,1,0,0,0,1,1,0,1,0,1,1,1,1,1,0,1,0,0,1,1,1,0,0,1,1,0,0,1,1,1,0,0,1,0,1,1,0,1,0,1,1,1,1,0,0,1,1,0,0,1,1,1,1,0,1,0,0,1,1,1,1,0,1,1,0,0,1,0,0,1,1,1,1,1,0,0,0,0,1,0,0,1,0,1,1,0,0,1,1,1,0,1,0,1,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,1,1,1,1,1,1,1,0,0,1,0,0,0,1,0,0,0,1,0,1,0,0,0,1,0,1,1,1,1,0,0,0,0,1,0,1,0,0,0}; + } + else + { + printf("unsupported dimension\n"); + return; + } + + test_knapsack_CRH_with_bit_out_gadget_internal(dimension, input_bits, digest_bits); +} + +template<> +void test_knapsack_CRH_with_bit_out_gadget >() +{ + typedef Fr FieldT; + const size_t dimension = knapsack_dimension::dimension; + const bit_vector input_bits = {1,1,0,0,1,0,1,0,0,1}; + bit_vector digest_bits; + + if (dimension == 1) + { + // hash_vector[0] = 5849873898117023322885358421738220900336335412351434682931015184050067928329141552099663 + digest_bits = {1,1,1,1,0,0,1,0,1,0,0,0,1,1,0,0,1,1,1,0,0,0,1,0,1,1,1,0,0,1,1,1,1,0,0,0,0,1,0,1,0,0,1,1,1,1,1,1,1,0,0,1,1,0,1,0,1,1,0,1,1,0,1,0,1,1,1,1,0,1,0,0,0,0,0,1,0,1,1,0,0,0,1,0,1,0,0,0,1,0,1,1,0,0,1,1,1,1,0,0,1,1,0,0,1,0,0,0,0,0,1,1,1,0,1,1,1,0,0,0,1,0,1,0,1,1,0,0,0,1,1,1,0,0,1,1,0,1,1,0,1,0,1,1,0,1,1,0,0,0,0,1,1,1,1,1,1,1,0,1,0,1,0,0,0,0,0,1,1,1,1,0,0,0,1,0,0,1,1,1,0,0,0,1,1,1,1,1,1,0,1,0,1,0,0,1,1,0,0,1,1,1,1,0,0,0,1,0,0,0,0,1,0,1,0,1,0,0,1,0,0,1,1,0,1,1,1,1,0,0,1,1,0,0,1,1,0,1,0,1,1,0,1,1,1,0,0,1,1,1,1,1,0,1,0,0,0,1,0,0,1,1,1,0,1,1,0,1,1,0,0,1,1,0,0,0,0,0,1,0,1,1,0,0,0,0,1,1,1,1,0,1,0,0,0,0,0,0}; + } + else if (dimension == 3) + { + // hash_vector[0] = 5849873898117023322885358421738220900336335412351434682931015184050067928329141552099663 + // hash_vector[1] = 53446030978469113922159049491079907226345854023550415464933501524860510292000093404219846 + // hash_vector[2] = 40260485387428589838404886401807432179330884659708615614555389829794909143554684402611550 + digest_bits = {1,1,1,1,0,0,1,0,1,0,0,0,1,1,0,0,1,1,1,0,0,0,1,0,1,1,1,0,0,1,1,1,1,0,0,0,0,1,0,1,0,0,1,1,1,1,1,1,1,0,0,1,1,0,1,0,1,1,0,1,1,0,1,0,1,1,1,1,0,1,0,0,0,0,0,1,0,1,1,0,0,0,1,0,1,0,0,0,1,0,1,1,0,0,1,1,1,1,0,0,1,1,0,0,1,0,0,0,0,0,1,1,1,0,1,1,1,0,0,0,1,0,1,0,1,1,0,0,0,1,1,1,0,0,1,1,0,1,1,0,1,0,1,1,0,1,1,0,0,0,0,1,1,1,1,1,1,1,0,1,0,1,0,0,0,0,0,1,1,1,1,0,0,0,1,0,0,1,1,1,0,0,0,1,1,1,1,1,1,0,1,0,1,0,0,1,1,0,0,1,1,1,1,0,0,0,1,0,0,0,0,1,0,1,0,1,0,0,1,0,0,1,1,0,1,1,1,1,0,0,1,1,0,0,1,1,0,1,0,1,1,0,1,1,1,0,0,1,1,1,1,1,0,1,0,0,0,1,0,0,1,1,1,0,1,1,0,1,1,0,0,1,1,0,0,0,0,0,1,0,1,1,0,0,0,0,1,1,1,1,0,1,0,0,0,0,0,0,0,1,1,0,0,0,1,1,1,0,0,1,0,0,1,0,1,0,1,0,1,1,1,0,0,0,0,0,0,1,1,1,1,1,0,1,0,0,0,1,1,1,1,0,1,0,0,1,0,0,1,1,1,1,0,1,1,0,1,1,0,1,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,1,0,0,1,1,1,1,0,0,0,0,0,0,1,1,1,1,0,1,1,1,1,1,0,1,1,0,0,1,1,1,1,1,0,1,0,1,0,1,0,1,0,0,0,1,1,0,0,1,1,0,0,1,1,1,1,1,1,1,1,0,1,0,0,1,0,1,0,1,1,1,1,1,0,1,1,1,1,0,0,1,0,1,1,0,0,1,0,0,1,0,1,0,1,1,0,1,1,0,1,0,1,0,0,0,0,0,1,0,1,1,0,1,0,1,0,0,0,1,1,1,0,1,1,0,0,1,0,1,0,0,1,1,0,1,1,0,0,0,1,0,0,0,0,0,1,1,1,1,1,1,0,1,1,0,0,0,1,1,1,0,0,0,1,0,0,1,1,1,1,0,1,1,0,1,1,0,1,0,0,0,1,0,0,1,0,0,1,1,1,1,1,0,1,1,0,0,1,0,1,1,1,1,0,1,1,1,0,1,1,0,1,0,1,1,0,0,0,0,1,1,1,1,0,1,0,1,0,1,0,1,1,0,0,1,0,1,1,1,1,1,1,0,0,0,0,1,0,0,0,1,1,0,1,0,1,0,0,0,1,0,1,1,0,0,0,1,1,0,0,1,0,0,1,1,0,0,1,0,1,0,0,0,1,1,1,0,0,1,1,1,0,0,0,1,1,0,1,1,0,1,1,0,1,0,0,1,1,0,1,0,0,0,0,1,1,0,1,0,0,0,0,1,1,0,1,1,0,1,0,1,1,1,1,0,1,0,1,1,0,0,0,1,1,1,0,1,0,0,1,0,1,0,1,1,1,1,1,0,0,0,1,0,0,0,1,1,1,1,1,1,1,0,1,0,1,0,1,1,1,1,1,0,1,0,0,1,1,1,0,0,1,1,0,0,1,1,1,0,0,1,0,1,1,0,1,0,1,1,1,1,0,0,1,1,0,0,1,1,1,1,0,1,0,0,1,1,1,1,0,1,1,0,0,1,0,0,1,1,1,1,1,0,0,0,0,1,0,0,1,0,1,1,0,0,1,1,1,0,1,0,1,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,1,1,1,1,1,1,1,0,0,1,0,0,0,1,0,0,0,1,0,1,0,0,0,1,0,1,1,1,1,0,0,0,0,1,0,1,0,0,0}; + } + else + { + printf("unsupported dimension\n"); + return; + } + + test_knapsack_CRH_with_bit_out_gadget_internal(dimension, input_bits, digest_bits); +} + +} // libsnark + +using namespace libsnark; + +int main(void) +{ +#ifdef CURVE_BN128 // BN128 has fancy dependencies so it may be disabled + bn128_pp::init_public_params(); + test_knapsack_CRH_with_bit_out_gadget >(); +#endif + edwards_pp::init_public_params(); + test_knapsack_CRH_with_bit_out_gadget >(); + mnt4_pp::init_public_params(); + test_knapsack_CRH_with_bit_out_gadget >(); + mnt6_pp::init_public_params(); + test_knapsack_CRH_with_bit_out_gadget >(); +} diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/hashes/sha256/sha256_aux.hpp b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/hashes/sha256/sha256_aux.hpp new file mode 100644 index 0000000..e0c7a7e --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/hashes/sha256/sha256_aux.hpp @@ -0,0 +1,160 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for auxiliary gadgets for the SHA256 gadget. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef SHA256_AUX_HPP_ +#define SHA256_AUX_HPP_ + +#include "gadgetlib1/gadgets/basic_gadgets.hpp" + +namespace libsnark { + +template +class lastbits_gadget : public gadget { +public: + pb_variable X; + size_t X_bits; + pb_variable result; + pb_linear_combination_array result_bits; + + pb_linear_combination_array full_bits; + std::shared_ptr > unpack_bits; + std::shared_ptr > pack_result; + + lastbits_gadget(protoboard &pb, + const pb_variable &X, + const size_t X_bits, + const pb_variable &result, + const pb_linear_combination_array &result_bits, + const std::string &annotation_prefix); + + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +template +class XOR3_gadget : public gadget { +private: + pb_variable tmp; +public: + pb_linear_combination A; + pb_linear_combination B; + pb_linear_combination C; + bool assume_C_is_zero; + pb_linear_combination out; + + XOR3_gadget(protoboard &pb, + const pb_linear_combination &A, + const pb_linear_combination &B, + const pb_linear_combination &C, + const bool assume_C_is_zero, + const pb_linear_combination &out, + const std::string &annotation_prefix); + + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +/* Page 10 of http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf */ +template +class small_sigma_gadget : public gadget { +private: + pb_variable_array W; + pb_variable result; +public: + pb_variable_array result_bits; + std::vector > > compute_bits; + std::shared_ptr > pack_result; + + small_sigma_gadget(protoboard &pb, + const pb_variable_array &W, + const pb_variable &result, + const size_t rot1, + const size_t rot2, + const size_t shift, + const std::string &annotation_prefix); + + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +/* Page 10 of http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf */ +template +class big_sigma_gadget : public gadget { +private: + pb_linear_combination_array W; + pb_variable result; +public: + pb_variable_array result_bits; + std::vector > > compute_bits; + std::shared_ptr > pack_result; + + big_sigma_gadget(protoboard &pb, + const pb_linear_combination_array &W, + const pb_variable &result, + const size_t rot1, + const size_t rot2, + const size_t rot3, + const std::string &annotation_prefix); + + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +/* Page 10 of http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf */ +template +class choice_gadget : public gadget { +private: + pb_variable_array result_bits; +public: + pb_linear_combination_array X; + pb_linear_combination_array Y; + pb_linear_combination_array Z; + pb_variable result; + std::shared_ptr > pack_result; + + choice_gadget(protoboard &pb, + const pb_linear_combination_array &X, + const pb_linear_combination_array &Y, + const pb_linear_combination_array &Z, + const pb_variable &result, const std::string &annotation_prefix); + + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +/* Page 10 of http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf */ +template +class majority_gadget : public gadget { +private: + pb_variable_array result_bits; + std::shared_ptr > pack_result; +public: + pb_linear_combination_array X; + pb_linear_combination_array Y; + pb_linear_combination_array Z; + pb_variable result; + + majority_gadget(protoboard &pb, + const pb_linear_combination_array &X, + const pb_linear_combination_array &Y, + const pb_linear_combination_array &Z, + const pb_variable &result, + const std::string &annotation_prefix); + + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +} // libsnark + +#include "gadgetlib1/gadgets/hashes/sha256/sha256_aux.tcc" + +#endif // SHA256_AUX_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/hashes/sha256/sha256_aux.tcc b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/hashes/sha256/sha256_aux.tcc new file mode 100644 index 0000000..8ab67be --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/hashes/sha256/sha256_aux.tcc @@ -0,0 +1,297 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for auxiliary gadgets for the SHA256 gadget. + + See sha256_aux.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef SHA256_AUX_TCC_ +#define SHA256_AUX_TCC_ + +namespace libsnark { + +template +lastbits_gadget::lastbits_gadget(protoboard &pb, + const pb_variable &X, + const size_t X_bits, + const pb_variable &result, + const pb_linear_combination_array &result_bits, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), + X(X), + X_bits(X_bits), + result(result), + result_bits(result_bits) +{ + full_bits = result_bits; + for (size_t i = result_bits.size(); i < X_bits; ++i) + { + pb_variable full_bits_overflow; + full_bits_overflow.allocate(pb, FMT(this->annotation_prefix, " full_bits_%zu", i)); + full_bits.emplace_back(full_bits_overflow); + } + + unpack_bits.reset(new packing_gadget(pb, full_bits, X, FMT(this->annotation_prefix, " unpack_bits"))); + pack_result.reset(new packing_gadget(pb, result_bits, result, FMT(this->annotation_prefix, " pack_result"))); +} + +template +void lastbits_gadget::generate_r1cs_constraints() +{ + unpack_bits->generate_r1cs_constraints(true); + pack_result->generate_r1cs_constraints(false); +} + +template +void lastbits_gadget::generate_r1cs_witness() +{ + unpack_bits->generate_r1cs_witness_from_packed(); + pack_result->generate_r1cs_witness_from_bits(); +} + +template +XOR3_gadget::XOR3_gadget(protoboard &pb, + const pb_linear_combination &A, + const pb_linear_combination &B, + const pb_linear_combination &C, + const bool assume_C_is_zero, + const pb_linear_combination &out, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), + A(A), + B(B), + C(C), + assume_C_is_zero(assume_C_is_zero), + out(out) +{ + if (!assume_C_is_zero) + { + tmp.allocate(pb, FMT(this->annotation_prefix, " tmp")); + } +} + +template +void XOR3_gadget::generate_r1cs_constraints() +{ + /* + tmp = A + B - 2AB i.e. tmp = A xor B + out = tmp + C - 2tmp C i.e. out = tmp xor C + */ + if (assume_C_is_zero) + { + this->pb.add_r1cs_constraint(r1cs_constraint(2*A, B, A + B - out), FMT(this->annotation_prefix, " implicit_tmp_equals_out")); + } + else + { + this->pb.add_r1cs_constraint(r1cs_constraint(2*A, B, A + B - tmp), FMT(this->annotation_prefix, " tmp")); + this->pb.add_r1cs_constraint(r1cs_constraint(2 * tmp, C, tmp + C - out), FMT(this->annotation_prefix, " out")); + } +} + +template +void XOR3_gadget::generate_r1cs_witness() +{ + if (assume_C_is_zero) + { + this->pb.lc_val(out) = this->pb.lc_val(A) + this->pb.lc_val(B) - FieldT(2) * this->pb.lc_val(A) * this->pb.lc_val(B); + } + else + { + this->pb.val(tmp) = this->pb.lc_val(A) + this->pb.lc_val(B) - FieldT(2) * this->pb.lc_val(A) * this->pb.lc_val(B); + this->pb.lc_val(out) = this->pb.val(tmp) + this->pb.lc_val(C) - FieldT(2) * this->pb.val(tmp) * this->pb.lc_val(C); + } +} + +#define SHA256_GADGET_ROTR(A, i, k) A[((i)+(k)) % 32] + +/* Page 10 of http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf */ +template +small_sigma_gadget::small_sigma_gadget(protoboard &pb, + const pb_variable_array &W, + const pb_variable &result, + const size_t rot1, + const size_t rot2, + const size_t shift, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), + W(W), + result(result) +{ + result_bits.allocate(pb, 32, FMT(this->annotation_prefix, " result_bits")); + compute_bits.resize(32); + for (size_t i = 0; i < 32; ++i) + { + compute_bits[i].reset(new XOR3_gadget(pb, SHA256_GADGET_ROTR(W, i, rot1), SHA256_GADGET_ROTR(W, i, rot2), + (i + shift < 32 ? W[i+shift] : ONE), + (i + shift >= 32), result_bits[i], + FMT(this->annotation_prefix, " compute_bits_%zu", i))); + } + pack_result.reset(new packing_gadget(pb, result_bits, result, FMT(this->annotation_prefix, " pack_result"))); +} + +template +void small_sigma_gadget::generate_r1cs_constraints() +{ + for (size_t i = 0; i < 32; ++i) + { + compute_bits[i]->generate_r1cs_constraints(); + } + + pack_result->generate_r1cs_constraints(false); +} + +template +void small_sigma_gadget::generate_r1cs_witness() +{ + for (size_t i = 0; i < 32; ++i) + { + compute_bits[i]->generate_r1cs_witness(); + } + + pack_result->generate_r1cs_witness_from_bits(); +} + +template +big_sigma_gadget::big_sigma_gadget(protoboard &pb, + const pb_linear_combination_array &W, + const pb_variable &result, + const size_t rot1, + const size_t rot2, + const size_t rot3, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), + W(W), + result(result) +{ + result_bits.allocate(pb, 32, FMT(this->annotation_prefix, " result_bits")); + compute_bits.resize(32); + for (size_t i = 0; i < 32; ++i) + { + compute_bits[i].reset(new XOR3_gadget(pb, SHA256_GADGET_ROTR(W, i, rot1), SHA256_GADGET_ROTR(W, i, rot2), SHA256_GADGET_ROTR(W, i, rot3), false, result_bits[i], + FMT(this->annotation_prefix, " compute_bits_%zu", i))); + } + + pack_result.reset(new packing_gadget(pb, result_bits, result, FMT(this->annotation_prefix, " pack_result"))); +} + +template +void big_sigma_gadget::generate_r1cs_constraints() +{ + for (size_t i = 0; i < 32; ++i) + { + compute_bits[i]->generate_r1cs_constraints(); + } + + pack_result->generate_r1cs_constraints(false); +} + +template +void big_sigma_gadget::generate_r1cs_witness() +{ + for (size_t i = 0; i < 32; ++i) + { + compute_bits[i]->generate_r1cs_witness(); + } + + pack_result->generate_r1cs_witness_from_bits(); +} + +/* Page 10 of http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf */ +template +choice_gadget::choice_gadget(protoboard &pb, + const pb_linear_combination_array &X, + const pb_linear_combination_array &Y, + const pb_linear_combination_array &Z, + const pb_variable &result, const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), + X(X), + Y(Y), + Z(Z), + result(result) +{ + result_bits.allocate(pb, 32, FMT(this->annotation_prefix, " result_bits")); + pack_result.reset(new packing_gadget(pb, result_bits, result, FMT(this->annotation_prefix, " result"))); +} + +template +void choice_gadget::generate_r1cs_constraints() +{ + for (size_t i = 0; i < 32; ++i) + { + /* + result = x * y + (1-x) * z + result - z = x * (y - z) + */ + this->pb.add_r1cs_constraint(r1cs_constraint(X[i], Y[i] - Z[i], result_bits[i] - Z[i]), FMT(this->annotation_prefix, " result_bits_%zu", i)); + } + pack_result->generate_r1cs_constraints(false); +} + +template +void choice_gadget::generate_r1cs_witness() +{ + for (size_t i = 0; i < 32; ++i) + { + this->pb.val(result_bits[i]) = this->pb.lc_val(X[i]) * this->pb.lc_val(Y[i]) + (FieldT::one() - this->pb.lc_val(X[i])) * this->pb.lc_val(Z[i]); + } + pack_result->generate_r1cs_witness_from_bits(); +} + +/* Page 10 of http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf */ +template +majority_gadget::majority_gadget(protoboard &pb, + const pb_linear_combination_array &X, + const pb_linear_combination_array &Y, + const pb_linear_combination_array &Z, + const pb_variable &result, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), + X(X), + Y(Y), + Z(Z), + result(result) +{ + result_bits.allocate(pb, 32, FMT(this->annotation_prefix, " result_bits")); + pack_result.reset(new packing_gadget(pb, result_bits, result, FMT(this->annotation_prefix, " result"))); +} + +template +void majority_gadget::generate_r1cs_constraints() +{ + for (size_t i = 0; i < 32; ++i) + { + /* + 2*result + aux = x + y + z + x, y, z, aux -- bits + aux = x + y + z - 2*result + */ + generate_boolean_r1cs_constraint(this->pb, result_bits[i], FMT(this->annotation_prefix, " result_%zu", i)); + this->pb.add_r1cs_constraint(r1cs_constraint(X[i] + Y[i] + Z[i] - 2 * result_bits[i], + 1 - (X[i] + Y[i] + Z[i] - 2 * result_bits[i]), + 0), + FMT(this->annotation_prefix, " result_bits_%zu", i)); + } + pack_result->generate_r1cs_constraints(false); +} + +template +void majority_gadget::generate_r1cs_witness() +{ + for (size_t i = 0; i < 32; ++i) + { + const long v = (this->pb.lc_val(X[i]) + this->pb.lc_val(Y[i]) + this->pb.lc_val(Z[i])).as_ulong(); + this->pb.val(result_bits[i]) = FieldT(v / 2); + } + + pack_result->generate_r1cs_witness_from_bits(); +} + +} // libsnark + +#endif // SHA256_AUX_TCC_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/hashes/sha256/sha256_components.hpp b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/hashes/sha256/sha256_components.hpp new file mode 100644 index 0000000..c2f31e3 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/hashes/sha256/sha256_components.hpp @@ -0,0 +1,108 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for gadgets for the SHA256 message schedule and round function. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef SHA256_COMPONENTS_HPP_ +#define SHA256_COMPONENTS_HPP_ + +#include "gadgetlib1/gadgets/basic_gadgets.hpp" +#include "gadgetlib1/gadgets/hashes/hash_io.hpp" +#include "gadgetlib1/gadgets/hashes/sha256/sha256_aux.hpp" + +namespace libsnark { + +const size_t SHA256_digest_size = 256; +const size_t SHA256_block_size = 512; + +template +pb_linear_combination_array SHA256_default_IV(protoboard &pb); + +template +class sha256_message_schedule_gadget : public gadget { +public: + std::vector > W_bits; + std::vector > > pack_W; + + std::vector > sigma0; + std::vector > sigma1; + std::vector > > compute_sigma0; + std::vector > > compute_sigma1; + std::vector > unreduced_W; + std::vector > > mod_reduce_W; +public: + pb_variable_array M; + pb_variable_array packed_W; + sha256_message_schedule_gadget(protoboard &pb, + const pb_variable_array &M, + const pb_variable_array &packed_W, + const std::string &annotation_prefix); + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +template +class sha256_round_function_gadget : public gadget { +public: + pb_variable sigma0; + pb_variable sigma1; + std::shared_ptr > compute_sigma0; + std::shared_ptr > compute_sigma1; + pb_variable choice; + pb_variable majority; + std::shared_ptr > compute_choice; + std::shared_ptr > compute_majority; + pb_variable packed_d; + std::shared_ptr > pack_d; + pb_variable packed_h; + std::shared_ptr > pack_h; + pb_variable unreduced_new_a; + pb_variable unreduced_new_e; + std::shared_ptr > mod_reduce_new_a; + std::shared_ptr > mod_reduce_new_e; + pb_variable packed_new_a; + pb_variable packed_new_e; +public: + pb_linear_combination_array a; + pb_linear_combination_array b; + pb_linear_combination_array c; + pb_linear_combination_array d; + pb_linear_combination_array e; + pb_linear_combination_array f; + pb_linear_combination_array g; + pb_linear_combination_array h; + pb_variable W; + long K; + pb_linear_combination_array new_a; + pb_linear_combination_array new_e; + + sha256_round_function_gadget(protoboard &pb, + const pb_linear_combination_array &a, + const pb_linear_combination_array &b, + const pb_linear_combination_array &c, + const pb_linear_combination_array &d, + const pb_linear_combination_array &e, + const pb_linear_combination_array &f, + const pb_linear_combination_array &g, + const pb_linear_combination_array &h, + const pb_variable &W, + const long &K, + const pb_linear_combination_array &new_a, + const pb_linear_combination_array &new_e, + const std::string &annotation_prefix); + + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +} // libsnark + +#include "gadgetlib1/gadgets/hashes/sha256/sha256_components.tcc" + +#endif // SHA256_COMPONENTS_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/hashes/sha256/sha256_components.tcc b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/hashes/sha256/sha256_components.tcc new file mode 100644 index 0000000..e8f233a --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/hashes/sha256/sha256_components.tcc @@ -0,0 +1,250 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for gadgets for the SHA256 message schedule and round function. + + See sha256_components.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef SHA256_COMPONENTS_TCC_ +#define SHA256_COMPONENTS_TCC_ + +namespace libsnark { + +const unsigned long SHA256_K[64] = { + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, + 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, + 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, + 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, + 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, + 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 +}; + +const unsigned long SHA256_H[8] = { + 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19 +}; + +template +pb_linear_combination_array SHA256_default_IV(protoboard &pb) +{ + pb_linear_combination_array result; + result.reserve(SHA256_digest_size); + + for (size_t i = 0; i < SHA256_digest_size; ++i) + { + int iv_val = (SHA256_H[i / 32] >> (31-(i % 32))) & 1; + + pb_linear_combination iv_element; + iv_element.assign(pb, iv_val * ONE); + iv_element.evaluate(pb); + + result.emplace_back(iv_element); + } + + return result; +} + +template +sha256_message_schedule_gadget::sha256_message_schedule_gadget(protoboard &pb, + const pb_variable_array &M, + const pb_variable_array &packed_W, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), + M(M), + packed_W(packed_W) +{ + W_bits.resize(64); + + pack_W.resize(16); + for (size_t i = 0; i < 16; ++i) + { + W_bits[i] = pb_variable_array(M.rbegin() + (15-i) * 32, M.rbegin() + (16-i) * 32); + pack_W[i].reset(new packing_gadget(pb, W_bits[i], packed_W[i], FMT(this->annotation_prefix, " pack_W_%zu", i))); + } + + /* NB: some of those will be un-allocated */ + sigma0.resize(64); + sigma1.resize(64); + compute_sigma0.resize(64); + compute_sigma1.resize(64); + unreduced_W.resize(64); + mod_reduce_W.resize(64); + + for (size_t i = 16; i < 64; ++i) + { + /* allocate result variables for sigma0/sigma1 invocations */ + sigma0[i].allocate(pb, FMT(this->annotation_prefix, " sigma0_%zu", i)); + sigma1[i].allocate(pb, FMT(this->annotation_prefix, " sigma1_%zu", i)); + + /* compute sigma0/sigma1 */ + compute_sigma0[i].reset(new small_sigma_gadget(pb, W_bits[i-15], sigma0[i], 7, 18, 3, FMT(this->annotation_prefix, " compute_sigma0_%zu", i))); + compute_sigma1[i].reset(new small_sigma_gadget(pb, W_bits[i-2], sigma1[i], 17, 19, 10, FMT(this->annotation_prefix, " compute_sigma1_%zu", i))); + + /* unreduced_W = sigma0(W_{i-15}) + sigma1(W_{i-2}) + W_{i-7} + W_{i-16} before modulo 2^32 */ + unreduced_W[i].allocate(pb, FMT(this->annotation_prefix, "unreduced_W_%zu", i)); + + /* allocate the bit representation of packed_W[i] */ + W_bits[i].allocate(pb, 32, FMT(this->annotation_prefix, " W_bits_%zu", i)); + + /* and finally reduce this into packed and bit representations */ + mod_reduce_W[i].reset(new lastbits_gadget(pb, unreduced_W[i], 32+2, packed_W[i], W_bits[i], FMT(this->annotation_prefix, " mod_reduce_W_%zu", i))); + } +} + +template +void sha256_message_schedule_gadget::generate_r1cs_constraints() +{ + for (size_t i = 0; i < 16; ++i) + { + pack_W[i]->generate_r1cs_constraints(false); // do not enforce bitness here; caller be aware. + } + + for (size_t i = 16; i < 64; ++i) + { + compute_sigma0[i]->generate_r1cs_constraints(); + compute_sigma1[i]->generate_r1cs_constraints(); + + this->pb.add_r1cs_constraint(r1cs_constraint(1, + sigma0[i] + sigma1[i] + packed_W[i-16] + packed_W[i-7], + unreduced_W[i]), + FMT(this->annotation_prefix, " unreduced_W_%zu", i)); + + mod_reduce_W[i]->generate_r1cs_constraints(); + } +} + +template +void sha256_message_schedule_gadget::generate_r1cs_witness() +{ + for (size_t i = 0; i < 16; ++i) + { + pack_W[i]->generate_r1cs_witness_from_bits(); + } + + for (size_t i = 16; i < 64; ++i) + { + compute_sigma0[i]->generate_r1cs_witness(); + compute_sigma1[i]->generate_r1cs_witness(); + + this->pb.val(unreduced_W[i]) = this->pb.val(sigma0[i]) + this->pb.val(sigma1[i]) + this->pb.val(packed_W[i-16]) + this->pb.val(packed_W[i-7]); + mod_reduce_W[i]->generate_r1cs_witness(); + } +} + +template +sha256_round_function_gadget::sha256_round_function_gadget(protoboard &pb, + const pb_linear_combination_array &a, + const pb_linear_combination_array &b, + const pb_linear_combination_array &c, + const pb_linear_combination_array &d, + const pb_linear_combination_array &e, + const pb_linear_combination_array &f, + const pb_linear_combination_array &g, + const pb_linear_combination_array &h, + const pb_variable &W, + const long &K, + const pb_linear_combination_array &new_a, + const pb_linear_combination_array &new_e, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), + a(a), + b(b), + c(c), + d(d), + e(e), + f(f), + g(g), + h(h), + W(W), + K(K), + new_a(new_a), + new_e(new_e) +{ + /* compute sigma0 and sigma1 */ + sigma0.allocate(pb, FMT(this->annotation_prefix, " sigma0")); + sigma1.allocate(pb, FMT(this->annotation_prefix, " sigma1")); + compute_sigma0.reset(new big_sigma_gadget(pb, a, sigma0, 2, 13, 22, FMT(this->annotation_prefix, " compute_sigma0"))); + compute_sigma1.reset(new big_sigma_gadget(pb, e, sigma1, 6, 11, 25, FMT(this->annotation_prefix, " compute_sigma1"))); + + /* compute choice */ + choice.allocate(pb, FMT(this->annotation_prefix, " choice")); + compute_choice.reset(new choice_gadget(pb, e, f, g, choice, FMT(this->annotation_prefix, " compute_choice"))); + + /* compute majority */ + majority.allocate(pb, FMT(this->annotation_prefix, " majority")); + compute_majority.reset(new majority_gadget(pb, a, b, c, majority, FMT(this->annotation_prefix, " compute_majority"))); + + /* pack d */ + packed_d.allocate(pb, FMT(this->annotation_prefix, " packed_d")); + pack_d.reset(new packing_gadget(pb, d, packed_d, FMT(this->annotation_prefix, " pack_d"))); + + /* pack h */ + packed_h.allocate(pb, FMT(this->annotation_prefix, " packed_h")); + pack_h.reset(new packing_gadget(pb, h, packed_h, FMT(this->annotation_prefix, " pack_h"))); + + /* compute the actual results for the round */ + unreduced_new_a.allocate(pb, FMT(this->annotation_prefix, " unreduced_new_a")); + unreduced_new_e.allocate(pb, FMT(this->annotation_prefix, " unreduced_new_e")); + + packed_new_a.allocate(pb, FMT(this->annotation_prefix, " packed_new_a")); + packed_new_e.allocate(pb, FMT(this->annotation_prefix, " packed_new_e")); + + mod_reduce_new_a.reset(new lastbits_gadget(pb, unreduced_new_a, 32+3, packed_new_a, new_a, FMT(this->annotation_prefix, " mod_reduce_new_a"))); + mod_reduce_new_e.reset(new lastbits_gadget(pb, unreduced_new_e, 32+3, packed_new_e, new_e, FMT(this->annotation_prefix, " mod_reduce_new_e"))); +} + +template +void sha256_round_function_gadget::generate_r1cs_constraints() +{ + compute_sigma0->generate_r1cs_constraints(); + compute_sigma1->generate_r1cs_constraints(); + + compute_choice->generate_r1cs_constraints(); + compute_majority->generate_r1cs_constraints(); + + pack_d->generate_r1cs_constraints(false); + pack_h->generate_r1cs_constraints(false); + + this->pb.add_r1cs_constraint(r1cs_constraint(1, + packed_h + sigma1 + choice + K + W + sigma0 + majority, + unreduced_new_a), + FMT(this->annotation_prefix, " unreduced_new_a")); + + this->pb.add_r1cs_constraint(r1cs_constraint(1, + packed_d + packed_h + sigma1 + choice + K + W, + unreduced_new_e), + FMT(this->annotation_prefix, " unreduced_new_e")); + + mod_reduce_new_a->generate_r1cs_constraints(); + mod_reduce_new_e->generate_r1cs_constraints(); +} + +template +void sha256_round_function_gadget::generate_r1cs_witness() +{ + compute_sigma0->generate_r1cs_witness(); + compute_sigma1->generate_r1cs_witness(); + + compute_choice->generate_r1cs_witness(); + compute_majority->generate_r1cs_witness(); + + pack_d->generate_r1cs_witness_from_bits(); + pack_h->generate_r1cs_witness_from_bits(); + + this->pb.val(unreduced_new_a) = this->pb.val(packed_h) + this->pb.val(sigma1) + this->pb.val(choice) + FieldT(K) + this->pb.val(W) + this->pb.val(sigma0) + this->pb.val(majority); + this->pb.val(unreduced_new_e) = this->pb.val(packed_d) + this->pb.val(packed_h) + this->pb.val(sigma1) + this->pb.val(choice) + FieldT(K) + this->pb.val(W); + + mod_reduce_new_a->generate_r1cs_witness(); + mod_reduce_new_e->generate_r1cs_witness(); +} + +} // libsnark + +#endif // SHA256_COMPONENTS_TCC_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/hashes/sha256/sha256_gadget.hpp b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/hashes/sha256/sha256_gadget.hpp new file mode 100644 index 0000000..8cb6365 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/hashes/sha256/sha256_gadget.hpp @@ -0,0 +1,98 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for top-level SHA256 gadgets. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef SHA256_GADGET_HPP_ +#define SHA256_GADGET_HPP_ + +#include "common/data_structures/merkle_tree.hpp" +#include "gadgetlib1/gadgets/basic_gadgets.hpp" +#include "gadgetlib1/gadgets/hashes/hash_io.hpp" +#include "gadgetlib1/gadgets/hashes/sha256/sha256_components.hpp" + +namespace libsnark { + +/** + * Gadget for the SHA256 compression function. + */ +template +class sha256_compression_function_gadget : public gadget { +public: + std::vector > round_a; + std::vector > round_b; + std::vector > round_c; + std::vector > round_d; + std::vector > round_e; + std::vector > round_f; + std::vector > round_g; + std::vector > round_h; + + pb_variable_array packed_W; + std::shared_ptr > message_schedule; + std::vector > round_functions; + + pb_variable_array unreduced_output; + pb_variable_array reduced_output; + std::vector > reduce_output; +public: + pb_linear_combination_array prev_output; + pb_variable_array new_block; + digest_variable output; + + sha256_compression_function_gadget(protoboard &pb, + const pb_linear_combination_array &prev_output, + const pb_variable_array &new_block, + const digest_variable &output, + const std::string &annotation_prefix); + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +/** + * Gadget for the SHA256 compression function, viewed as a 2-to-1 hash + * function, and using the same initialization vector as in SHA256 + * specification. Thus, any collision for + * sha256_two_to_one_hash_gadget trivially extends to a collision for + * full SHA256 (by appending the same padding). + */ +template +class sha256_two_to_one_hash_gadget : public gadget { +public: + typedef bit_vector hash_value_type; + typedef merkle_authentication_path merkle_authentication_path_type; + + std::shared_ptr > f; + + sha256_two_to_one_hash_gadget(protoboard &pb, + const digest_variable &left, + const digest_variable &right, + const digest_variable &output, + const std::string &annotation_prefix); + sha256_two_to_one_hash_gadget(protoboard &pb, + const size_t block_length, + const block_variable &input_block, + const digest_variable &output, + const std::string &annotation_prefix); + + void generate_r1cs_constraints(const bool ensure_output_bitness=true); // TODO: ignored for now + void generate_r1cs_witness(); + + static size_t get_block_len(); + static size_t get_digest_len(); + static bit_vector get_hash(const bit_vector &input); + + static size_t expected_constraints(const bool ensure_output_bitness=true); // TODO: ignored for now +}; + +} // libsnark + +#include "gadgetlib1/gadgets/hashes/sha256/sha256_gadget.tcc" + +#endif // SHA256_GADGET_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/hashes/sha256/sha256_gadget.tcc b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/hashes/sha256/sha256_gadget.tcc new file mode 100644 index 0000000..fc7ac98 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/hashes/sha256/sha256_gadget.tcc @@ -0,0 +1,230 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for top-level SHA256 gadgets. + + See sha256_gadget.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef SHA256_GADGET_TCC_ +#define SHA256_GADGET_TCC_ + +namespace libsnark { + +template +sha256_compression_function_gadget::sha256_compression_function_gadget(protoboard &pb, + const pb_linear_combination_array &prev_output, + const pb_variable_array &new_block, + const digest_variable &output, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), + prev_output(prev_output), + new_block(new_block), + output(output) +{ + /* message schedule and inputs for it */ + packed_W.allocate(pb, 64, FMT(this->annotation_prefix, " packed_W")); + message_schedule.reset(new sha256_message_schedule_gadget(pb, new_block, packed_W, FMT(this->annotation_prefix, " message_schedule"))); + + /* initalize */ + round_a.push_back(pb_linear_combination_array(prev_output.rbegin() + 7*32, prev_output.rbegin() + 8*32)); + round_b.push_back(pb_linear_combination_array(prev_output.rbegin() + 6*32, prev_output.rbegin() + 7*32)); + round_c.push_back(pb_linear_combination_array(prev_output.rbegin() + 5*32, prev_output.rbegin() + 6*32)); + round_d.push_back(pb_linear_combination_array(prev_output.rbegin() + 4*32, prev_output.rbegin() + 5*32)); + round_e.push_back(pb_linear_combination_array(prev_output.rbegin() + 3*32, prev_output.rbegin() + 4*32)); + round_f.push_back(pb_linear_combination_array(prev_output.rbegin() + 2*32, prev_output.rbegin() + 3*32)); + round_g.push_back(pb_linear_combination_array(prev_output.rbegin() + 1*32, prev_output.rbegin() + 2*32)); + round_h.push_back(pb_linear_combination_array(prev_output.rbegin() + 0*32, prev_output.rbegin() + 1*32)); + + /* do the rounds */ + for (size_t i = 0; i < 64; ++i) + { + round_h.push_back(round_g[i]); + round_g.push_back(round_f[i]); + round_f.push_back(round_e[i]); + round_d.push_back(round_c[i]); + round_c.push_back(round_b[i]); + round_b.push_back(round_a[i]); + + pb_variable_array new_round_a_variables; + new_round_a_variables.allocate(pb, 32, FMT(this->annotation_prefix, " new_round_a_variables_%zu", i+1)); + round_a.emplace_back(new_round_a_variables); + + pb_variable_array new_round_e_variables; + new_round_e_variables.allocate(pb, 32, FMT(this->annotation_prefix, " new_round_e_variables_%zu", i+1)); + round_e.emplace_back(new_round_e_variables); + + round_functions.push_back(sha256_round_function_gadget(pb, + round_a[i], round_b[i], round_c[i], round_d[i], + round_e[i], round_f[i], round_g[i], round_h[i], + packed_W[i], SHA256_K[i], round_a[i+1], round_e[i+1], + FMT(this->annotation_prefix, " round_functions_%zu", i))); + } + + /* finalize */ + unreduced_output.allocate(pb, 8, FMT(this->annotation_prefix, " unreduced_output")); + reduced_output.allocate(pb, 8, FMT(this->annotation_prefix, " reduced_output")); + for (size_t i = 0; i < 8; ++i) + { + reduce_output.push_back(lastbits_gadget(pb, + unreduced_output[i], + 32+1, + reduced_output[i], + pb_variable_array(output.bits.rbegin() + (7-i) * 32, output.bits.rbegin() + (8-i) * 32), + FMT(this->annotation_prefix, " reduce_output_%zu", i))); + } +} + +template +void sha256_compression_function_gadget::generate_r1cs_constraints() +{ + message_schedule->generate_r1cs_constraints(); + for (size_t i = 0; i < 64; ++i) + { + round_functions[i].generate_r1cs_constraints(); + } + + for (size_t i = 0; i < 4; ++i) + { + this->pb.add_r1cs_constraint(r1cs_constraint(1, + round_functions[3-i].packed_d + round_functions[63-i].packed_new_a, + unreduced_output[i]), + FMT(this->annotation_prefix, " unreduced_output_%zu", i)); + + this->pb.add_r1cs_constraint(r1cs_constraint(1, + round_functions[3-i].packed_h + round_functions[63-i].packed_new_e, + unreduced_output[4+i]), + FMT(this->annotation_prefix, " unreduced_output_%zu", 4+i)); + } + + for (size_t i = 0; i < 8; ++i) + { + reduce_output[i].generate_r1cs_constraints(); + } +} + +template +void sha256_compression_function_gadget::generate_r1cs_witness() +{ + message_schedule->generate_r1cs_witness(); + +#ifdef DEBUG + printf("Input:\n"); + for (size_t j = 0; j < 16; ++j) + { + printf("%lx ", this->pb.val(packed_W[j]).as_ulong()); + } + printf("\n"); +#endif + + for (size_t i = 0; i < 64; ++i) + { + round_functions[i].generate_r1cs_witness(); + } + + for (size_t i = 0; i < 4; ++i) + { + this->pb.val(unreduced_output[i]) = this->pb.val(round_functions[3-i].packed_d) + this->pb.val(round_functions[63-i].packed_new_a); + this->pb.val(unreduced_output[4+i]) = this->pb.val(round_functions[3-i].packed_h) + this->pb.val(round_functions[63-i].packed_new_e); + } + + for (size_t i = 0; i < 8; ++i) + { + reduce_output[i].generate_r1cs_witness(); + } + +#ifdef DEBUG + printf("Output:\n"); + for (size_t j = 0; j < 8; ++j) + { + printf("%lx ", this->pb.val(reduced_output[j]).as_ulong()); + } + printf("\n"); +#endif +} + +template +sha256_two_to_one_hash_gadget::sha256_two_to_one_hash_gadget(protoboard &pb, + const digest_variable &left, + const digest_variable &right, + const digest_variable &output, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix) +{ + /* concatenate block = left || right */ + pb_variable_array block; + block.insert(block.end(), left.bits.begin(), left.bits.end()); + block.insert(block.end(), right.bits.begin(), right.bits.end()); + + /* compute the hash itself */ + f.reset(new sha256_compression_function_gadget(pb, SHA256_default_IV(pb), block, output, FMT(this->annotation_prefix, " f"))); +} + +template +sha256_two_to_one_hash_gadget::sha256_two_to_one_hash_gadget(protoboard &pb, + const size_t block_length, + const block_variable &input_block, + const digest_variable &output, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix) +{ + assert(block_length == SHA256_block_size); + assert(input_block.bits.size() == block_length); + f.reset(new sha256_compression_function_gadget(pb, SHA256_default_IV(pb), input_block.bits, output, FMT(this->annotation_prefix, " f"))); +} + +template +void sha256_two_to_one_hash_gadget::generate_r1cs_constraints(const bool ensure_output_bitness) +{ + UNUSED(ensure_output_bitness); + f->generate_r1cs_constraints(); +} + +template +void sha256_two_to_one_hash_gadget::generate_r1cs_witness() +{ + f->generate_r1cs_witness(); +} + +template +size_t sha256_two_to_one_hash_gadget::get_block_len() +{ + return SHA256_block_size; +} + +template +size_t sha256_two_to_one_hash_gadget::get_digest_len() +{ + return SHA256_digest_size; +} + +template +bit_vector sha256_two_to_one_hash_gadget::get_hash(const bit_vector &input) +{ + protoboard pb; + + block_variable input_variable(pb, SHA256_block_size, "input"); + digest_variable output_variable(pb, SHA256_digest_size, "output"); + sha256_two_to_one_hash_gadget f(pb, SHA256_block_size, input_variable, output_variable, "f"); + + input_variable.generate_r1cs_witness(input); + f.generate_r1cs_witness(); + + return output_variable.get_digest(); +} + +template +size_t sha256_two_to_one_hash_gadget::expected_constraints(const bool ensure_output_bitness) +{ + UNUSED(ensure_output_bitness); + return 27280; /* hardcoded for now */ +} + +} // libsnark + +#endif // SHA256_GADGET_TCC_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/hashes/sha256/tests/generate_sha256_gadget_tests.py b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/hashes/sha256/tests/generate_sha256_gadget_tests.py new file mode 100644 index 0000000..452317f --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/hashes/sha256/tests/generate_sha256_gadget_tests.py @@ -0,0 +1,55 @@ +#!/usr/bin/env python +## +# @author This file is part of libsnark, developed by SCIPR Lab +# and contributors (see AUTHORS). +# @copyright MIT license (see LICENSE file) + +import random +import pypy_sha256 # PyPy's implementation of SHA256 compression function; see copyright and authorship notice within. + +BLOCK_LEN = 512 +BLOCK_BYTES = BLOCK_LEN // 8 +HASH_LEN = 256 +HASH_BYTES = HASH_LEN // 8 + +def gen_random_bytes(n): + return [random.randint(0, 255) for i in xrange(n)] + +def words_to_bytes(arr): + return sum(([x >> 24, (x >> 16) & 0xff, (x >> 8) & 0xff, x & 0xff] for x in arr), []) + +def bytes_to_words(arr): + l = len(arr) + assert l % 4 == 0 + return [(arr[i*4 + 3] << 24) + (arr[i*4+2] << 16) + (arr[i*4+1] << 8) + arr[i*4] for i in xrange(l//4)] + +def cpp_val(s, log_radix=32): + if log_radix == 8: + hexfmt = '0x%02x' + elif log_radix == 32: + hexfmt = '0x%08x' + s = bytes_to_words(s) + else: + raise + return 'int_list_to_bits({%s}, %d)' % (', '.join(hexfmt % x for x in s), log_radix) + +def H_bytes(x): + assert len(x) == BLOCK_BYTES + state = pypy_sha256.sha_init() + state['data'] = words_to_bytes(bytes_to_words(x)) + pypy_sha256.sha_transform(state) + return words_to_bytes(bytes_to_words(words_to_bytes(state['digest']))) + +def generate_sha256_gadget_tests(): + left = gen_random_bytes(HASH_BYTES) + right = gen_random_bytes(HASH_BYTES) + hash = H_bytes(left + right) + + print "const bit_vector left_bv = %s;" % cpp_val(left) + print "const bit_vector right_bv = %s;" % cpp_val(right) + print "const bit_vector hash_bv = %s;" % cpp_val(hash) + +if __name__ == '__main__': + random.seed(0) # for reproducibility + generate_sha256_gadget_tests() + diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/hashes/sha256/tests/pypy_sha256.py b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/hashes/sha256/tests/pypy_sha256.py new file mode 100644 index 0000000..496989c --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/hashes/sha256/tests/pypy_sha256.py @@ -0,0 +1,263 @@ +#!/usr/bin/env python +# +# SHA256 compression function implementation below is a verbatim copy of PyPy's implementation from +# https://bitbucket.org/pypy/pypy/raw/f1f064b3faf1e012f7a9a9ab08f18074637ebe8a/lib_pypy/_sha256.py . +# +# It is licensed under the MIT license and copyright PyPy Copyright holders 2003-2015 +# See https://bitbucket.org/pypy/pypy/src/tip/LICENSE for the full copyright notice. +# + +SHA_BLOCKSIZE = 64 +SHA_DIGESTSIZE = 32 + + +def new_shaobject(): + return { + 'digest': [0]*8, + 'count_lo': 0, + 'count_hi': 0, + 'data': [0]* SHA_BLOCKSIZE, + 'local': 0, + 'digestsize': 0 + } + +ROR = lambda x, y: (((x & 0xffffffff) >> (y & 31)) | (x << (32 - (y & 31)))) & 0xffffffff +Ch = lambda x, y, z: (z ^ (x & (y ^ z))) +Maj = lambda x, y, z: (((x | y) & z) | (x & y)) +S = lambda x, n: ROR(x, n) +R = lambda x, n: (x & 0xffffffff) >> n +Sigma0 = lambda x: (S(x, 2) ^ S(x, 13) ^ S(x, 22)) +Sigma1 = lambda x: (S(x, 6) ^ S(x, 11) ^ S(x, 25)) +Gamma0 = lambda x: (S(x, 7) ^ S(x, 18) ^ R(x, 3)) +Gamma1 = lambda x: (S(x, 17) ^ S(x, 19) ^ R(x, 10)) + +def sha_transform(sha_info): + W = [] + + d = sha_info['data'] + for i in range(0,16): + W.append( (d[4*i]<<24) + (d[4*i+1]<<16) + (d[4*i+2]<<8) + d[4*i+3]) + + for i in range(16,64): + W.append( (Gamma1(W[i - 2]) + W[i - 7] + Gamma0(W[i - 15]) + W[i - 16]) & 0xffffffff ) + + ss = sha_info['digest'][:] + + def RND(a,b,c,d,e,f,g,h,i,ki): + t0 = h + Sigma1(e) + Ch(e, f, g) + ki + W[i]; + t1 = Sigma0(a) + Maj(a, b, c); + d += t0; + h = t0 + t1; + return d & 0xffffffff, h & 0xffffffff + + ss[3], ss[7] = RND(ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],0,0x428a2f98); + ss[2], ss[6] = RND(ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],1,0x71374491); + ss[1], ss[5] = RND(ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],2,0xb5c0fbcf); + ss[0], ss[4] = RND(ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],3,0xe9b5dba5); + ss[7], ss[3] = RND(ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],4,0x3956c25b); + ss[6], ss[2] = RND(ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],5,0x59f111f1); + ss[5], ss[1] = RND(ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],6,0x923f82a4); + ss[4], ss[0] = RND(ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],7,0xab1c5ed5); + ss[3], ss[7] = RND(ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],8,0xd807aa98); + ss[2], ss[6] = RND(ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],9,0x12835b01); + ss[1], ss[5] = RND(ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],10,0x243185be); + ss[0], ss[4] = RND(ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],11,0x550c7dc3); + ss[7], ss[3] = RND(ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],12,0x72be5d74); + ss[6], ss[2] = RND(ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],13,0x80deb1fe); + ss[5], ss[1] = RND(ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],14,0x9bdc06a7); + ss[4], ss[0] = RND(ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],15,0xc19bf174); + ss[3], ss[7] = RND(ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],16,0xe49b69c1); + ss[2], ss[6] = RND(ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],17,0xefbe4786); + ss[1], ss[5] = RND(ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],18,0x0fc19dc6); + ss[0], ss[4] = RND(ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],19,0x240ca1cc); + ss[7], ss[3] = RND(ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],20,0x2de92c6f); + ss[6], ss[2] = RND(ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],21,0x4a7484aa); + ss[5], ss[1] = RND(ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],22,0x5cb0a9dc); + ss[4], ss[0] = RND(ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],23,0x76f988da); + ss[3], ss[7] = RND(ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],24,0x983e5152); + ss[2], ss[6] = RND(ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],25,0xa831c66d); + ss[1], ss[5] = RND(ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],26,0xb00327c8); + ss[0], ss[4] = RND(ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],27,0xbf597fc7); + ss[7], ss[3] = RND(ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],28,0xc6e00bf3); + ss[6], ss[2] = RND(ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],29,0xd5a79147); + ss[5], ss[1] = RND(ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],30,0x06ca6351); + ss[4], ss[0] = RND(ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],31,0x14292967); + ss[3], ss[7] = RND(ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],32,0x27b70a85); + ss[2], ss[6] = RND(ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],33,0x2e1b2138); + ss[1], ss[5] = RND(ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],34,0x4d2c6dfc); + ss[0], ss[4] = RND(ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],35,0x53380d13); + ss[7], ss[3] = RND(ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],36,0x650a7354); + ss[6], ss[2] = RND(ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],37,0x766a0abb); + ss[5], ss[1] = RND(ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],38,0x81c2c92e); + ss[4], ss[0] = RND(ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],39,0x92722c85); + ss[3], ss[7] = RND(ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],40,0xa2bfe8a1); + ss[2], ss[6] = RND(ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],41,0xa81a664b); + ss[1], ss[5] = RND(ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],42,0xc24b8b70); + ss[0], ss[4] = RND(ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],43,0xc76c51a3); + ss[7], ss[3] = RND(ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],44,0xd192e819); + ss[6], ss[2] = RND(ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],45,0xd6990624); + ss[5], ss[1] = RND(ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],46,0xf40e3585); + ss[4], ss[0] = RND(ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],47,0x106aa070); + ss[3], ss[7] = RND(ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],48,0x19a4c116); + ss[2], ss[6] = RND(ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],49,0x1e376c08); + ss[1], ss[5] = RND(ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],50,0x2748774c); + ss[0], ss[4] = RND(ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],51,0x34b0bcb5); + ss[7], ss[3] = RND(ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],52,0x391c0cb3); + ss[6], ss[2] = RND(ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],53,0x4ed8aa4a); + ss[5], ss[1] = RND(ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],54,0x5b9cca4f); + ss[4], ss[0] = RND(ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],55,0x682e6ff3); + ss[3], ss[7] = RND(ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],56,0x748f82ee); + ss[2], ss[6] = RND(ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],57,0x78a5636f); + ss[1], ss[5] = RND(ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],58,0x84c87814); + ss[0], ss[4] = RND(ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],59,0x8cc70208); + ss[7], ss[3] = RND(ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],60,0x90befffa); + ss[6], ss[2] = RND(ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],61,0xa4506ceb); + ss[5], ss[1] = RND(ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],62,0xbef9a3f7); + ss[4], ss[0] = RND(ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],63,0xc67178f2); + + dig = [] + for i, x in enumerate(sha_info['digest']): + dig.append( (x + ss[i]) & 0xffffffff ) + sha_info['digest'] = dig + +def sha_init(): + sha_info = new_shaobject() + sha_info['digest'] = [0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A, 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19] + sha_info['count_lo'] = 0 + sha_info['count_hi'] = 0 + sha_info['local'] = 0 + sha_info['digestsize'] = 32 + return sha_info + +def sha224_init(): + sha_info = new_shaobject() + sha_info['digest'] = [0xc1059ed8, 0x367cd507, 0x3070dd17, 0xf70e5939, 0xffc00b31, 0x68581511, 0x64f98fa7, 0xbefa4fa4] + sha_info['count_lo'] = 0 + sha_info['count_hi'] = 0 + sha_info['local'] = 0 + sha_info['digestsize'] = 28 + return sha_info + +def sha_update(sha_info, buffer): + if isinstance(buffer, str): + raise TypeError("Unicode strings must be encoded before hashing") + count = len(buffer) + buffer_idx = 0 + clo = (sha_info['count_lo'] + (count << 3)) & 0xffffffff + if clo < sha_info['count_lo']: + sha_info['count_hi'] += 1 + sha_info['count_lo'] = clo + + sha_info['count_hi'] += (count >> 29) + + if sha_info['local']: + i = SHA_BLOCKSIZE - sha_info['local'] + if i > count: + i = count + + # copy buffer + sha_info['data'][sha_info['local']:sha_info['local']+i] = buffer[buffer_idx:buffer_idx+i] + + count -= i + buffer_idx += i + + sha_info['local'] += i + if sha_info['local'] == SHA_BLOCKSIZE: + sha_transform(sha_info) + sha_info['local'] = 0 + else: + return + + while count >= SHA_BLOCKSIZE: + # copy buffer + sha_info['data'] = list(buffer[buffer_idx:buffer_idx + SHA_BLOCKSIZE]) + count -= SHA_BLOCKSIZE + buffer_idx += SHA_BLOCKSIZE + sha_transform(sha_info) + + + # copy buffer + pos = sha_info['local'] + sha_info['data'][pos:pos+count] = buffer[buffer_idx:buffer_idx + count] + sha_info['local'] = count + +def sha_final(sha_info): + lo_bit_count = sha_info['count_lo'] + hi_bit_count = sha_info['count_hi'] + count = (lo_bit_count >> 3) & 0x3f + sha_info['data'][count] = 0x80; + count += 1 + if count > SHA_BLOCKSIZE - 8: + # zero the bytes in data after the count + sha_info['data'] = sha_info['data'][:count] + ([0] * (SHA_BLOCKSIZE - count)) + sha_transform(sha_info) + # zero bytes in data + sha_info['data'] = [0] * SHA_BLOCKSIZE + else: + sha_info['data'] = sha_info['data'][:count] + ([0] * (SHA_BLOCKSIZE - count)) + + sha_info['data'][56] = (hi_bit_count >> 24) & 0xff + sha_info['data'][57] = (hi_bit_count >> 16) & 0xff + sha_info['data'][58] = (hi_bit_count >> 8) & 0xff + sha_info['data'][59] = (hi_bit_count >> 0) & 0xff + sha_info['data'][60] = (lo_bit_count >> 24) & 0xff + sha_info['data'][61] = (lo_bit_count >> 16) & 0xff + sha_info['data'][62] = (lo_bit_count >> 8) & 0xff + sha_info['data'][63] = (lo_bit_count >> 0) & 0xff + + sha_transform(sha_info) + + dig = [] + for i in sha_info['digest']: + dig.extend([ ((i>>24) & 0xff), ((i>>16) & 0xff), ((i>>8) & 0xff), (i & 0xff) ]) + return ''.join([chr(i) for i in dig]) + +class sha256(object): + digest_size = digestsize = SHA_DIGESTSIZE + block_size = SHA_BLOCKSIZE + + def __init__(self, s=None): + self._sha = sha_init() + if s: + sha_update(self._sha, s) + + def update(self, s): + sha_update(self._sha, s) + + def digest(self): + return sha_final(self._sha.copy())[:self._sha['digestsize']] + + def hexdigest(self): + return ''.join(['%.2x' % ord(i) for i in self.digest()]) + + def copy(self): + new = sha256.__new__(sha256) + new._sha = self._sha.copy() + return new + +class sha224(sha256): + digest_size = digestsize = 28 + + def __init__(self, s=None): + self._sha = sha224_init() + if s: + sha_update(self._sha, s) + + def copy(self): + new = sha224.__new__(sha224) + new._sha = self._sha.copy() + return new + +def test(): + a_str = "just a test string" + + assert 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855' == sha256().hexdigest() + assert 'd7b553c6f09ac85d142415f857c5310f3bbbe7cdd787cce4b985acedd585266f' == sha256(a_str).hexdigest() + assert '8113ebf33c97daa9998762aacafe750c7cefc2b2f173c90c59663a57fe626f21' == sha256(a_str*7).hexdigest() + + s = sha256(a_str) + s.update(a_str) + assert '03d9963e05a094593190b6fc794cb1a3e1ac7d7883f0b5855268afeccc70d461' == s.hexdigest() + +if __name__ == "__main__": + test() diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/hashes/sha256/tests/test_sha256_gadget.cpp b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/hashes/sha256/tests/test_sha256_gadget.cpp new file mode 100644 index 0000000..471928f --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/hashes/sha256/tests/test_sha256_gadget.cpp @@ -0,0 +1,46 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include "common/default_types/ec_pp.hpp" +#include "common/utils.hpp" +#include "common/profiling.hpp" +#include "gadgetlib1/gadgets/hashes/sha256/sha256_gadget.hpp" + +using namespace libsnark; + +template +void test_two_to_one() +{ + protoboard pb; + + digest_variable left(pb, SHA256_digest_size, "left"); + digest_variable right(pb, SHA256_digest_size, "right"); + digest_variable output(pb, SHA256_digest_size, "output"); + + sha256_two_to_one_hash_gadget f(pb, left, right, output, "f"); + f.generate_r1cs_constraints(); + printf("Number of constraints for sha256_two_to_one_hash_gadget: %zu\n", pb.num_constraints()); + + const bit_vector left_bv = int_list_to_bits({0x426bc2d8, 0x4dc86782, 0x81e8957a, 0x409ec148, 0xe6cffbe8, 0xafe6ba4f, 0x9c6f1978, 0xdd7af7e9}, 32); + const bit_vector right_bv = int_list_to_bits({0x038cce42, 0xabd366b8, 0x3ede7e00, 0x9130de53, 0x72cdf73d, 0xee825114, 0x8cb48d1b, 0x9af68ad0}, 32); + const bit_vector hash_bv = int_list_to_bits({0xeffd0b7f, 0x1ccba116, 0x2ee816f7, 0x31c62b48, 0x59305141, 0x990e5c0a, 0xce40d33d, 0x0b1167d1}, 32); + + left.generate_r1cs_witness(left_bv); + right.generate_r1cs_witness(right_bv); + + f.generate_r1cs_witness(); + output.generate_r1cs_witness(hash_bv); + + assert(pb.is_satisfied()); +} + +int main(void) +{ + start_profiling(); + default_ec_pp::init_public_params(); + test_two_to_one >(); +} diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/merkle_tree/merkle_authentication_path_variable.hpp b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/merkle_tree/merkle_authentication_path_variable.hpp new file mode 100644 index 0000000..0efa7cf --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/merkle_tree/merkle_authentication_path_variable.hpp @@ -0,0 +1,38 @@ +/** + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef MERKLE_AUTHENTICATION_PATH_VARIABLE_HPP_ +#define MERKLE_AUTHENTICATION_PATH_VARIABLE_HPP_ + +#include "common/data_structures/merkle_tree.hpp" +#include "gadgetlib1/gadget.hpp" +#include "gadgetlib1/gadgets/hashes/hash_io.hpp" + +namespace libsnark { + +template +class merkle_authentication_path_variable : public gadget { +public: + + const size_t tree_depth; + std::vector > left_digests; + std::vector > right_digests; + + merkle_authentication_path_variable(protoboard &pb, + const size_t tree_depth, + const std::string &annotation_prefix); + + void generate_r1cs_constraints(); + void generate_r1cs_witness(const size_t address, const merkle_authentication_path &path); + merkle_authentication_path get_authentication_path(const size_t address) const; +}; + +} // libsnark + +#include "gadgetlib1/gadgets/merkle_tree/merkle_authentication_path_variable.tcc" + +#endif // MERKLE_AUTHENTICATION_PATH_VARIABLE_HPP diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/merkle_tree/merkle_authentication_path_variable.tcc b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/merkle_tree/merkle_authentication_path_variable.tcc new file mode 100644 index 0000000..d773051 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/merkle_tree/merkle_authentication_path_variable.tcc @@ -0,0 +1,76 @@ +/** + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef MERKLE_AUTHENTICATION_PATH_VARIABLE_TCC_ +#define MERKLE_AUTHENTICATION_PATH_VARIABLE_TCC_ + +namespace libsnark { + +template +merkle_authentication_path_variable::merkle_authentication_path_variable(protoboard &pb, + const size_t tree_depth, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), + tree_depth(tree_depth) +{ + for (size_t i = 0; i < tree_depth; ++i) + { + left_digests.emplace_back(digest_variable(pb, HashT::get_digest_len(), FMT(annotation_prefix, " left_digests_%zu", i))); + right_digests.emplace_back(digest_variable(pb, HashT::get_digest_len(), FMT(annotation_prefix, " right_digests_%zu", i))); + } +} + +template +void merkle_authentication_path_variable::generate_r1cs_constraints() +{ + for (size_t i = 0; i < tree_depth; ++i) + { + left_digests[i].generate_r1cs_constraints(); + right_digests[i].generate_r1cs_constraints(); + } +} + +template +void merkle_authentication_path_variable::generate_r1cs_witness(const size_t address, const merkle_authentication_path &path) +{ + assert(path.size() == tree_depth); + + for (size_t i = 0; i < tree_depth; ++i) + { + if (address & (1ul << (tree_depth-1-i))) + { + left_digests[i].generate_r1cs_witness(path[i]); + } + else + { + right_digests[i].generate_r1cs_witness(path[i]); + } + } +} + +template +merkle_authentication_path merkle_authentication_path_variable::get_authentication_path(const size_t address) const +{ + merkle_authentication_path result; + for (size_t i = 0; i < tree_depth; ++i) + { + if (address & (1ul << (tree_depth-1-i))) + { + result.emplace_back(left_digests[i].get_digest()); + } + else + { + result.emplace_back(right_digests[i].get_digest()); + } + } + + return result; +} + +} // libsnark + +#endif // MERKLE_AUTHENTICATION_PATH_VARIABLE_TCC diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/merkle_tree/merkle_tree_check_read_gadget.hpp b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/merkle_tree/merkle_tree_check_read_gadget.hpp new file mode 100644 index 0000000..2663774 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/merkle_tree/merkle_tree_check_read_gadget.hpp @@ -0,0 +1,74 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for the Merkle tree check read gadget. + + The gadget checks the following: given a root R, address A, value V, and + authentication path P, check that P is a valid authentication path for the + value V as the A-th leaf in a Merkle tree with root R. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef MERKLE_TREE_CHECK_READ_GADGET_HPP_ +#define MERKLE_TREE_CHECK_READ_GADGET_HPP_ + +#include "common/data_structures/merkle_tree.hpp" +#include "gadgetlib1/gadget.hpp" +#include "gadgetlib1/gadgets/hashes/crh_gadget.hpp" +#include "gadgetlib1/gadgets/hashes/hash_io.hpp" +#include "gadgetlib1/gadgets/hashes/digest_selector_gadget.hpp" +#include "gadgetlib1/gadgets/merkle_tree/merkle_authentication_path_variable.hpp" + +namespace libsnark { + +template +class merkle_tree_check_read_gadget : public gadget { +private: + + std::vector hashers; + std::vector > hasher_inputs; + std::vector > propagators; + std::vector > internal_output; + + std::shared_ptr > computed_root; + std::shared_ptr > check_root; + +public: + + const size_t digest_size; + const size_t tree_depth; + pb_linear_combination_array address_bits; + digest_variable leaf; + digest_variable root; + merkle_authentication_path_variable path; + pb_linear_combination read_successful; + + merkle_tree_check_read_gadget(protoboard &pb, + const size_t tree_depth, + const pb_linear_combination_array &address_bits, + const digest_variable &leaf_digest, + const digest_variable &root_digest, + const merkle_authentication_path_variable &path, + const pb_linear_combination &read_successful, + const std::string &annotation_prefix); + + void generate_r1cs_constraints(); + void generate_r1cs_witness(); + + static size_t root_size_in_bits(); + /* for debugging purposes */ + static size_t expected_constraints(const size_t tree_depth); +}; + +template +void test_merkle_tree_check_read_gadget(); + +} // libsnark + +#include "gadgetlib1/gadgets/merkle_tree/merkle_tree_check_read_gadget.tcc" + +#endif // MERKLE_TREE_CHECK_READ_GADGET_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/merkle_tree/merkle_tree_check_read_gadget.tcc b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/merkle_tree/merkle_tree_check_read_gadget.tcc new file mode 100644 index 0000000..6002a58 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/merkle_tree/merkle_tree_check_read_gadget.tcc @@ -0,0 +1,196 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for the Merkle tree check read. + + See merkle_tree_check_read_gadget.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef MERKLE_TREE_CHECK_READ_GADGET_TCC_ +#define MERKLE_TREE_CHECK_READ_GADGET_TCC_ + +namespace libsnark { + +template +merkle_tree_check_read_gadget::merkle_tree_check_read_gadget(protoboard &pb, + const size_t tree_depth, + const pb_linear_combination_array &address_bits, + const digest_variable &leaf, + const digest_variable &root, + const merkle_authentication_path_variable &path, + const pb_linear_combination &read_successful, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), + digest_size(HashT::get_digest_len()), + tree_depth(tree_depth), + address_bits(address_bits), + leaf(leaf), + root(root), + path(path), + read_successful(read_successful) +{ + /* + The tricky part here is ordering. For Merkle tree + authentication paths, path[0] corresponds to one layer below + the root (and path[tree_depth-1] corresponds to the layer + containing the leaf), while address_bits has the reverse order: + address_bits[0] is LSB, and corresponds to layer containing the + leaf, and address_bits[tree_depth-1] is MSB, and corresponds to + the subtree directly under the root. + */ + assert(tree_depth > 0); + assert(tree_depth == address_bits.size()); + + for (size_t i = 0; i < tree_depth-1; ++i) + { + internal_output.emplace_back(digest_variable(pb, digest_size, FMT(this->annotation_prefix, " internal_output_%zu", i))); + } + + computed_root.reset(new digest_variable(pb, digest_size, FMT(this->annotation_prefix, " computed_root"))); + + for (size_t i = 0; i < tree_depth; ++i) + { + block_variable inp(pb, path.left_digests[i], path.right_digests[i], FMT(this->annotation_prefix, " inp_%zu", i)); + hasher_inputs.emplace_back(inp); + hashers.emplace_back(HashT(pb, 2*digest_size, inp, (i == 0 ? *computed_root : internal_output[i-1]), + FMT(this->annotation_prefix, " load_hashers_%zu", i))); + } + + for (size_t i = 0; i < tree_depth; ++i) + { + /* + The propagators take a computed hash value (or leaf in the + base case) and propagate it one layer up, either in the left + or the right slot of authentication_path_variable. + */ + propagators.emplace_back(digest_selector_gadget(pb, digest_size, i < tree_depth - 1 ? internal_output[i] : leaf, + address_bits[tree_depth-1-i], path.left_digests[i], path.right_digests[i], + FMT(this->annotation_prefix, " digest_selector_%zu", i))); + } + + check_root.reset(new bit_vector_copy_gadget(pb, computed_root->bits, root.bits, read_successful, FieldT::capacity(), FMT(annotation_prefix, " check_root"))); +} + +template +void merkle_tree_check_read_gadget::generate_r1cs_constraints() +{ + /* ensure correct hash computations */ + for (size_t i = 0; i < tree_depth; ++i) + { + // Note that we check root outside and have enforced booleanity of path.left_digests/path.right_digests outside in path.generate_r1cs_constraints + hashers[i].generate_r1cs_constraints(false); + } + + /* ensure consistency of path.left_digests/path.right_digests with internal_output */ + for (size_t i = 0; i < tree_depth; ++i) + { + propagators[i].generate_r1cs_constraints(); + } + + check_root->generate_r1cs_constraints(false, false); +} + +template +void merkle_tree_check_read_gadget::generate_r1cs_witness() +{ + /* do the hash computations bottom-up */ + for (int i = tree_depth-1; i >= 0; --i) + { + /* propagate previous input */ + propagators[i].generate_r1cs_witness(); + + /* compute hash */ + hashers[i].generate_r1cs_witness(); + } + + check_root->generate_r1cs_witness(); +} + +template +size_t merkle_tree_check_read_gadget::root_size_in_bits() +{ + return HashT::get_digest_len(); +} + +template +size_t merkle_tree_check_read_gadget::expected_constraints(const size_t tree_depth) +{ + /* NB: this includes path constraints */ + const size_t hasher_constraints = tree_depth * HashT::expected_constraints(false); + const size_t propagator_constraints = tree_depth * HashT::get_digest_len(); + const size_t authentication_path_constraints = 2 * tree_depth * HashT::get_digest_len(); + const size_t check_root_constraints = 3 * div_ceil(HashT::get_digest_len(), FieldT::capacity()); + + return hasher_constraints + propagator_constraints + authentication_path_constraints + check_root_constraints; +} + +template +void test_merkle_tree_check_read_gadget() +{ + /* prepare test */ + const size_t digest_len = HashT::get_digest_len(); + const size_t tree_depth = 16; + std::vector path(tree_depth); + + bit_vector prev_hash(digest_len); + std::generate(prev_hash.begin(), prev_hash.end(), [&]() { return std::rand() % 2; }); + bit_vector leaf = prev_hash; + + bit_vector address_bits; + + size_t address = 0; + for (long level = tree_depth-1; level >= 0; --level) + { + const bool computed_is_right = (std::rand() % 2); + address |= (computed_is_right ? 1ul << (tree_depth-1-level) : 0); + address_bits.push_back(computed_is_right); + bit_vector other(digest_len); + std::generate(other.begin(), other.end(), [&]() { return std::rand() % 2; }); + + bit_vector block = prev_hash; + block.insert(computed_is_right ? block.begin() : block.end(), other.begin(), other.end()); + bit_vector h = HashT::get_hash(block); + + path[level] = other; + + prev_hash = h; + } + bit_vector root = prev_hash; + + /* execute test */ + protoboard pb; + pb_variable_array address_bits_va; + address_bits_va.allocate(pb, tree_depth, "address_bits"); + digest_variable leaf_digest(pb, digest_len, "input_block"); + digest_variable root_digest(pb, digest_len, "output_digest"); + merkle_authentication_path_variable path_var(pb, tree_depth, "path_var"); + merkle_tree_check_read_gadget ml(pb, tree_depth, address_bits_va, leaf_digest, root_digest, path_var, ONE, "ml"); + + path_var.generate_r1cs_constraints(); + ml.generate_r1cs_constraints(); + + address_bits_va.fill_with_bits(pb, address_bits); + assert(address_bits_va.get_field_element_from_bits(pb).as_ulong() == address); + leaf_digest.generate_r1cs_witness(leaf); + path_var.generate_r1cs_witness(address, path); + ml.generate_r1cs_witness(); + + /* make sure that read checker didn't accidentally overwrite anything */ + address_bits_va.fill_with_bits(pb, address_bits); + leaf_digest.generate_r1cs_witness(leaf); + root_digest.generate_r1cs_witness(root); + assert(pb.is_satisfied()); + + const size_t num_constraints = pb.num_constraints(); + const size_t expected_constraints = merkle_tree_check_read_gadget::expected_constraints(tree_depth); + assert(num_constraints == expected_constraints); +} + +} // libsnark + +#endif // MERKLE_TREE_CHECK_READ_GADGET_TCC_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/merkle_tree/merkle_tree_check_update_gadget.hpp b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/merkle_tree/merkle_tree_check_update_gadget.hpp new file mode 100644 index 0000000..2d6840d --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/merkle_tree/merkle_tree_check_update_gadget.hpp @@ -0,0 +1,91 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for the Merkle tree check read gadget. + + The gadget checks the following: given two roots R1 and R2, address A, two + values V1 and V2, and authentication path P, check that + - P is a valid authentication path for the value V1 as the A-th leaf in a Merkle tree with root R1, and + - P is a valid authentication path for the value V2 as the A-th leaf in a Merkle tree with root R2. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef MERKLE_TREE_CHECK_UPDATE_GADGET_HPP_ +#define MERKLE_TREE_CHECK_UPDATE_GADGET_HPP_ + +#include "common/data_structures/merkle_tree.hpp" +#include "gadgetlib1/gadget.hpp" +#include "gadgetlib1/gadgets/hashes/crh_gadget.hpp" +#include "gadgetlib1/gadgets/hashes/hash_io.hpp" +#include "gadgetlib1/gadgets/hashes/digest_selector_gadget.hpp" +#include "gadgetlib1/gadgets/merkle_tree/merkle_authentication_path_variable.hpp" + +namespace libsnark { + +template +class merkle_tree_check_update_gadget : public gadget { +private: + + std::vector prev_hashers; + std::vector > prev_hasher_inputs; + std::vector > prev_propagators; + std::vector > prev_internal_output; + + std::vector next_hashers; + std::vector > next_hasher_inputs; + std::vector > next_propagators; + std::vector > next_internal_output; + + std::shared_ptr > computed_next_root; + std::shared_ptr > check_next_root; + +public: + + const size_t digest_size; + const size_t tree_depth; + + pb_variable_array address_bits; + digest_variable prev_leaf_digest; + digest_variable prev_root_digest; + merkle_authentication_path_variable prev_path; + digest_variable next_leaf_digest; + digest_variable next_root_digest; + merkle_authentication_path_variable next_path; + pb_linear_combination update_successful; + + /* Note that while it is necessary to generate R1CS constraints + for prev_path, it is not necessary to do so for next_path. See + comment in the implementation of generate_r1cs_constraints() */ + + merkle_tree_check_update_gadget(protoboard &pb, + const size_t tree_depth, + const pb_variable_array &address_bits, + const digest_variable &prev_leaf_digest, + const digest_variable &prev_root_digest, + const merkle_authentication_path_variable &prev_path, + const digest_variable &next_leaf_digest, + const digest_variable &next_root_digest, + const merkle_authentication_path_variable &next_path, + const pb_linear_combination &update_successful, + const std::string &annotation_prefix); + + void generate_r1cs_constraints(); + void generate_r1cs_witness(); + + static size_t root_size_in_bits(); + /* for debugging purposes */ + static size_t expected_constraints(const size_t tree_depth); +}; + +template +void test_merkle_tree_check_update_gadget(); + +} // libsnark + +#include "gadgetlib1/gadgets/merkle_tree/merkle_tree_check_update_gadget.tcc" + +#endif // MERKLE_TREE_CHECK_UPDATE_GADGET_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/merkle_tree/merkle_tree_check_update_gadget.tcc b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/merkle_tree/merkle_tree_check_update_gadget.tcc new file mode 100644 index 0000000..1ac08ed --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/merkle_tree/merkle_tree_check_update_gadget.tcc @@ -0,0 +1,265 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for the Merkle tree check update gadget. + + See merkle_tree_check_update_gadget.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef MERKLE_TREE_CHECK_UPDATE_GADGET_TCC_ +#define MERKLE_TREE_CHECK_UPDATE_GADGET_TCC_ + +namespace libsnark { + +template +merkle_tree_check_update_gadget::merkle_tree_check_update_gadget(protoboard &pb, + const size_t tree_depth, + const pb_variable_array &address_bits, + const digest_variable &prev_leaf_digest, + const digest_variable &prev_root_digest, + const merkle_authentication_path_variable &prev_path, + const digest_variable &next_leaf_digest, + const digest_variable &next_root_digest, + const merkle_authentication_path_variable &next_path, + const pb_linear_combination &update_successful, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), + digest_size(HashT::get_digest_len()), + tree_depth(tree_depth), + address_bits(address_bits), + prev_leaf_digest(prev_leaf_digest), + prev_root_digest(prev_root_digest), + prev_path(prev_path), + next_leaf_digest(next_leaf_digest), + next_root_digest(next_root_digest), + next_path(next_path), + update_successful(update_successful) +{ + assert(tree_depth > 0); + assert(tree_depth == address_bits.size()); + + for (size_t i = 0; i < tree_depth-1; ++i) + { + prev_internal_output.emplace_back(digest_variable(pb, digest_size, FMT(this->annotation_prefix, " prev_internal_output_%zu", i))); + next_internal_output.emplace_back(digest_variable(pb, digest_size, FMT(this->annotation_prefix, " next_internal_output_%zu", i))); + } + + computed_next_root.reset(new digest_variable(pb, digest_size, FMT(this->annotation_prefix, " computed_root"))); + + for (size_t i = 0; i < tree_depth; ++i) + { + block_variable prev_inp(pb, prev_path.left_digests[i], prev_path.right_digests[i], FMT(this->annotation_prefix, " prev_inp_%zu", i)); + prev_hasher_inputs.emplace_back(prev_inp); + prev_hashers.emplace_back(HashT(pb, 2*digest_size, prev_inp, (i == 0 ? prev_root_digest : prev_internal_output[i-1]), + FMT(this->annotation_prefix, " prev_hashers_%zu", i))); + + block_variable next_inp(pb, next_path.left_digests[i], next_path.right_digests[i], FMT(this->annotation_prefix, " next_inp_%zu", i)); + next_hasher_inputs.emplace_back(next_inp); + next_hashers.emplace_back(HashT(pb, 2*digest_size, next_inp, (i == 0 ? *computed_next_root : next_internal_output[i-1]), + FMT(this->annotation_prefix, " next_hashers_%zu", i))); + } + + for (size_t i = 0; i < tree_depth; ++i) + { + prev_propagators.emplace_back(digest_selector_gadget(pb, digest_size, i < tree_depth -1 ? prev_internal_output[i] : prev_leaf_digest, + address_bits[tree_depth-1-i], prev_path.left_digests[i], prev_path.right_digests[i], + FMT(this->annotation_prefix, " prev_propagators_%zu", i))); + next_propagators.emplace_back(digest_selector_gadget(pb, digest_size, i < tree_depth -1 ? next_internal_output[i] : next_leaf_digest, + address_bits[tree_depth-1-i], next_path.left_digests[i], next_path.right_digests[i], + FMT(this->annotation_prefix, " next_propagators_%zu", i))); + } + + check_next_root.reset(new bit_vector_copy_gadget(pb, computed_next_root->bits, next_root_digest.bits, update_successful, FieldT::capacity(), FMT(annotation_prefix, " check_next_root"))); +} + +template +void merkle_tree_check_update_gadget::generate_r1cs_constraints() +{ + /* ensure correct hash computations */ + for (size_t i = 0; i < tree_depth; ++i) + { + prev_hashers[i].generate_r1cs_constraints(false); // we check root outside and prev_left/prev_right above + next_hashers[i].generate_r1cs_constraints(true); // however we must check right side hashes + } + + /* ensure consistency of internal_left/internal_right with internal_output */ + for (size_t i = 0; i < tree_depth; ++i) + { + prev_propagators[i].generate_r1cs_constraints(); + next_propagators[i].generate_r1cs_constraints(); + } + + /* ensure that prev auxiliary input and next auxiliary input match */ + for (size_t i = 0; i < tree_depth; ++i) + { + for (size_t j = 0; j < digest_size; ++j) + { + /* + addr * (prev_left - next_left) + (1 - addr) * (prev_right - next_right) = 0 + addr * (prev_left - next_left - prev_right + next_right) = next_right - prev_right + */ + this->pb.add_r1cs_constraint(r1cs_constraint(address_bits[tree_depth-1-i], + prev_path.left_digests[i].bits[j] - next_path.left_digests[i].bits[j] - prev_path.right_digests[i].bits[j] + next_path.right_digests[i].bits[j], + next_path.right_digests[i].bits[j] - prev_path.right_digests[i].bits[j]), + FMT(this->annotation_prefix, " aux_check_%zu_%zu", i, j)); + } + } + + /* Note that while it is necessary to generate R1CS constraints + for prev_path, it is not necessary to do so for next_path. + + This holds, because { next_path.left_inputs[i], + next_path.right_inputs[i] } is a pair { hash_output, + auxiliary_input }. The bitness for hash_output is enforced + above by next_hashers[i].generate_r1cs_constraints. + + Because auxiliary input is the same for prev_path and next_path + (enforced above), we have that auxiliary_input part is also + constrained to be boolean, because prev_path is *all* + constrained to be all boolean. */ + + check_next_root->generate_r1cs_constraints(false, false); +} + +template +void merkle_tree_check_update_gadget::generate_r1cs_witness() +{ + /* do the hash computations bottom-up */ + for (int i = tree_depth-1; i >= 0; --i) + { + /* ensure consistency of prev_path and next_path */ + if (this->pb.val(address_bits[tree_depth-1-i]) == FieldT::one()) + { + next_path.left_digests[i].generate_r1cs_witness(prev_path.left_digests[i].get_digest()); + } + else + { + next_path.right_digests[i].generate_r1cs_witness(prev_path.right_digests[i].get_digest()); + } + + /* propagate previous input */ + prev_propagators[i].generate_r1cs_witness(); + next_propagators[i].generate_r1cs_witness(); + + /* compute hash */ + prev_hashers[i].generate_r1cs_witness(); + next_hashers[i].generate_r1cs_witness(); + } + + check_next_root->generate_r1cs_witness(); +} + +template +size_t merkle_tree_check_update_gadget::root_size_in_bits() +{ + return HashT::get_digest_len(); +} + +template +size_t merkle_tree_check_update_gadget::expected_constraints(const size_t tree_depth) +{ + /* NB: this includes path constraints */ + const size_t prev_hasher_constraints = tree_depth * HashT::expected_constraints(false); + const size_t next_hasher_constraints = tree_depth * HashT::expected_constraints(true); + const size_t prev_authentication_path_constraints = 2 * tree_depth * HashT::get_digest_len(); + const size_t prev_propagator_constraints = tree_depth * HashT::get_digest_len(); + const size_t next_propagator_constraints = tree_depth * HashT::get_digest_len(); + const size_t check_next_root_constraints = 3 * div_ceil(HashT::get_digest_len(), FieldT::capacity()); + const size_t aux_equality_constraints = tree_depth * HashT::get_digest_len(); + + return (prev_hasher_constraints + next_hasher_constraints + prev_authentication_path_constraints + + prev_propagator_constraints + next_propagator_constraints + check_next_root_constraints + + aux_equality_constraints); +} + +template +void test_merkle_tree_check_update_gadget() +{ + /* prepare test */ + const size_t digest_len = HashT::get_digest_len(); + + const size_t tree_depth = 16; + std::vector prev_path(tree_depth); + + bit_vector prev_load_hash(digest_len); + std::generate(prev_load_hash.begin(), prev_load_hash.end(), [&]() { return std::rand() % 2; }); + bit_vector prev_store_hash(digest_len); + std::generate(prev_store_hash.begin(), prev_store_hash.end(), [&]() { return std::rand() % 2; }); + + bit_vector loaded_leaf = prev_load_hash; + bit_vector stored_leaf = prev_store_hash; + + bit_vector address_bits; + + size_t address = 0; + for (long level = tree_depth-1; level >= 0; --level) + { + const bool computed_is_right = (std::rand() % 2); + address |= (computed_is_right ? 1ul << (tree_depth-1-level) : 0); + address_bits.push_back(computed_is_right); + bit_vector other(digest_len); + std::generate(other.begin(), other.end(), [&]() { return std::rand() % 2; }); + + bit_vector load_block = prev_load_hash; + load_block.insert(computed_is_right ? load_block.begin() : load_block.end(), other.begin(), other.end()); + bit_vector store_block = prev_store_hash; + store_block.insert(computed_is_right ? store_block.begin() : store_block.end(), other.begin(), other.end()); + + bit_vector load_h = HashT::get_hash(load_block); + bit_vector store_h = HashT::get_hash(store_block); + + prev_path[level] = other; + + prev_load_hash = load_h; + prev_store_hash = store_h; + } + + bit_vector load_root = prev_load_hash; + bit_vector store_root = prev_store_hash; + + /* execute the test */ + protoboard pb; + pb_variable_array address_bits_va; + address_bits_va.allocate(pb, tree_depth, "address_bits"); + digest_variable prev_leaf_digest(pb, digest_len, "prev_leaf_digest"); + digest_variable prev_root_digest(pb, digest_len, "prev_root_digest"); + merkle_authentication_path_variable prev_path_var(pb, tree_depth, "prev_path_var"); + digest_variable next_leaf_digest(pb, digest_len, "next_leaf_digest"); + digest_variable next_root_digest(pb, digest_len, "next_root_digest"); + merkle_authentication_path_variable next_path_var(pb, tree_depth, "next_path_var"); + merkle_tree_check_update_gadget mls(pb, tree_depth, address_bits_va, + prev_leaf_digest, prev_root_digest, prev_path_var, + next_leaf_digest, next_root_digest, next_path_var, ONE, "mls"); + + prev_path_var.generate_r1cs_constraints(); + mls.generate_r1cs_constraints(); + + address_bits_va.fill_with_bits(pb, address_bits); + assert(address_bits_va.get_field_element_from_bits(pb).as_ulong() == address); + prev_leaf_digest.generate_r1cs_witness(loaded_leaf); + prev_path_var.generate_r1cs_witness(address, prev_path); + next_leaf_digest.generate_r1cs_witness(stored_leaf); + address_bits_va.fill_with_bits(pb, address_bits); + mls.generate_r1cs_witness(); + + /* make sure that update check will check for the right things */ + prev_leaf_digest.generate_r1cs_witness(loaded_leaf); + next_leaf_digest.generate_r1cs_witness(stored_leaf); + prev_root_digest.generate_r1cs_witness(load_root); + next_root_digest.generate_r1cs_witness(store_root); + address_bits_va.fill_with_bits(pb, address_bits); + assert(pb.is_satisfied()); + + const size_t num_constraints = pb.num_constraints(); + const size_t expected_constraints = merkle_tree_check_update_gadget::expected_constraints(tree_depth); + assert(num_constraints == expected_constraints); +} + +} // libsnark + +#endif // MERKLE_TREE_CHECK_UPDATE_GADGET_TCC_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/merkle_tree/tests/test_merkle_tree_gadgets.cpp b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/merkle_tree/tests/test_merkle_tree_gadgets.cpp new file mode 100644 index 0000000..8d52c57 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/merkle_tree/tests/test_merkle_tree_gadgets.cpp @@ -0,0 +1,48 @@ +/** + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifdef CURVE_BN128 +#include "algebra/curves/bn128/bn128_pp.hpp" +#endif +#include "algebra/curves/edwards/edwards_pp.hpp" +#include "algebra/curves/mnt/mnt4/mnt4_pp.hpp" +#include "algebra/curves/mnt/mnt6/mnt6_pp.hpp" +#include "gadgetlib1/gadgets/merkle_tree/merkle_tree_check_read_gadget.hpp" +#include "gadgetlib1/gadgets/merkle_tree/merkle_tree_check_update_gadget.hpp" +#include "gadgetlib1/gadgets/hashes/sha256/sha256_gadget.hpp" + +using namespace libsnark; + +template +void test_all_merkle_tree_gadgets() +{ + typedef Fr FieldT; + test_merkle_tree_check_read_gadget >(); + test_merkle_tree_check_read_gadget >(); + + test_merkle_tree_check_update_gadget >(); + test_merkle_tree_check_update_gadget >(); +} + +int main(void) +{ + start_profiling(); + +#ifdef CURVE_BN128 // BN128 has fancy dependencies so it may be disabled + bn128_pp::init_public_params(); + test_all_merkle_tree_gadgets(); +#endif + + edwards_pp::init_public_params(); + test_all_merkle_tree_gadgets(); + + mnt4_pp::init_public_params(); + test_all_merkle_tree_gadgets(); + + mnt6_pp::init_public_params(); + test_all_merkle_tree_gadgets(); +} diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/pairing/mnt_pairing_params.hpp b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/pairing/mnt_pairing_params.hpp new file mode 100644 index 0000000..1d6d30f --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/pairing/mnt_pairing_params.hpp @@ -0,0 +1,102 @@ +/** @file + ***************************************************************************** + + Declaration of specializations of pairing_selector to + - pairing_selector, and + - pairing_selector. + + See pairing_params.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef MNT_PAIRING_PARAMS_HPP_ +#define MNT_PAIRING_PARAMS_HPP_ + +#include "algebra/curves/mnt/mnt4/mnt4_pp.hpp" +#include "algebra/curves/mnt/mnt6/mnt6_pp.hpp" +#include "gadgetlib1/gadgets/pairing/pairing_params.hpp" +#include "gadgetlib1/gadgets/fields/fp2_gadgets.hpp" +#include "gadgetlib1/gadgets/fields/fp4_gadgets.hpp" +#include "gadgetlib1/gadgets/fields/fp3_gadgets.hpp" +#include "gadgetlib1/gadgets/fields/fp6_gadgets.hpp" + +namespace libsnark { + +template +class mnt_e_over_e_miller_loop_gadget; + +template +class mnt_e_times_e_over_e_miller_loop_gadget; + +template +class mnt4_final_exp_gadget; + +template +class mnt6_final_exp_gadget; + +/** + * Specialization for MNT4. + */ +template<> +class pairing_selector { +public: + typedef Fr FieldT; + typedef Fqe FqeT; + typedef Fqk FqkT; + + typedef Fp3_variable Fqe_variable_type; + typedef Fp3_mul_gadget Fqe_mul_gadget_type; + typedef Fp3_mul_by_lc_gadget Fqe_mul_by_lc_gadget_type; + typedef Fp3_sqr_gadget Fqe_sqr_gadget_type; + + typedef Fp6_variable Fqk_variable_type; + typedef Fp6_mul_gadget Fqk_mul_gadget_type; + typedef Fp6_mul_by_2345_gadget Fqk_special_mul_gadget_type; + typedef Fp6_sqr_gadget Fqk_sqr_gadget_type; + + typedef mnt6_pp other_curve_type; + + typedef mnt_e_over_e_miller_loop_gadget e_over_e_miller_loop_gadget_type; + typedef mnt_e_times_e_over_e_miller_loop_gadget e_times_e_over_e_miller_loop_gadget_type; + typedef mnt4_final_exp_gadget final_exp_gadget_type; + + static const constexpr bigint &pairing_loop_count = mnt6_ate_loop_count; +}; + +/** + * Specialization for MNT6. + */ +template<> +class pairing_selector { +public: + typedef Fr FieldT; + + typedef Fqe FqeT; + typedef Fqk FqkT; + + typedef Fp2_variable Fqe_variable_type; + typedef Fp2_mul_gadget Fqe_mul_gadget_type; + typedef Fp2_mul_by_lc_gadget Fqe_mul_by_lc_gadget_type; + typedef Fp2_sqr_gadget Fqe_sqr_gadget_type; + + typedef Fp4_variable Fqk_variable_type; + typedef Fp4_mul_gadget Fqk_mul_gadget_type; + typedef Fp4_mul_gadget Fqk_special_mul_gadget_type; + typedef Fp4_sqr_gadget Fqk_sqr_gadget_type; + + typedef mnt4_pp other_curve_type; + + typedef mnt_e_over_e_miller_loop_gadget e_over_e_miller_loop_gadget_type; + typedef mnt_e_times_e_over_e_miller_loop_gadget e_times_e_over_e_miller_loop_gadget_type; + typedef mnt6_final_exp_gadget final_exp_gadget_type; + + static const constexpr bigint &pairing_loop_count = mnt4_ate_loop_count; +}; + +} // libsnark + +#endif // MNT_PAIRING_PARAMS_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/pairing/pairing_checks.hpp b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/pairing/pairing_checks.hpp new file mode 100644 index 0000000..872a14d --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/pairing/pairing_checks.hpp @@ -0,0 +1,94 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for pairing-check gadgets. + + Given that e(.,.) denotes a pairing, + - the gadget "check_e_equals_e_gadget" checks the equation "e(P1,Q1)=e(P2,Q2)"; and + - the gadget "check_e_equals_ee_gadget" checks the equation "e(P1,Q1)=e(P2,Q2)*e(P3,Q3)". + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef PAIRING_CHECKS_HPP_ +#define PAIRING_CHECKS_HPP_ + +#include +#include "gadgetlib1/gadgets/pairing/pairing_params.hpp" +#include "gadgetlib1/gadgets/pairing/weierstrass_miller_loop.hpp" +#include "gadgetlib1/gadgets/pairing/weierstrass_final_exponentiation.hpp" + +namespace libsnark { + +template +class check_e_equals_e_gadget : public gadget > { +public: + + typedef Fr FieldT; + + std::shared_ptr > ratio; + std::shared_ptr > compute_ratio; + std::shared_ptr > check_finexp; + + G1_precomputation lhs_G1; + G2_precomputation lhs_G2; + G1_precomputation rhs_G1; + G2_precomputation rhs_G2; + + pb_variable result; + + check_e_equals_e_gadget(protoboard &pb, + const G1_precomputation &lhs_G1, + const G2_precomputation &lhs_G2, + const G1_precomputation &rhs_G1, + const G2_precomputation &rhs_G2, + const pb_variable &result, + const std::string &annotation_prefix); + + void generate_r1cs_constraints(); + + void generate_r1cs_witness(); +}; + +template +class check_e_equals_ee_gadget : public gadget > { +public: + + typedef Fr FieldT; + + std::shared_ptr > ratio; + std::shared_ptr > compute_ratio; + std::shared_ptr > check_finexp; + + G1_precomputation lhs_G1; + G2_precomputation lhs_G2; + G1_precomputation rhs1_G1; + G2_precomputation rhs1_G2; + G1_precomputation rhs2_G1; + G2_precomputation rhs2_G2; + + pb_variable result; + + check_e_equals_ee_gadget(protoboard &pb, + const G1_precomputation &lhs_G1, + const G2_precomputation &lhs_G2, + const G1_precomputation &rhs1_G1, + const G2_precomputation &rhs1_G2, + const G1_precomputation &rhs2_G1, + const G2_precomputation &rhs2_G2, + const pb_variable &result, + const std::string &annotation_prefix); + + void generate_r1cs_constraints(); + + void generate_r1cs_witness(); +}; + +} // libsnark + +#include "gadgetlib1/gadgets/pairing/pairing_checks.tcc" + +#endif // PAIRING_CHECKS_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/pairing/pairing_checks.tcc b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/pairing/pairing_checks.tcc new file mode 100644 index 0000000..65aa4a7 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/pairing/pairing_checks.tcc @@ -0,0 +1,93 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for pairing-check gadgets. + + See pairing_checks.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef PAIRING_CHECKS_TCC_ +#define PAIRING_CHECKS_TCC_ + +namespace libsnark { + +template +check_e_equals_e_gadget::check_e_equals_e_gadget(protoboard &pb, + const G1_precomputation &lhs_G1, + const G2_precomputation &lhs_G2, + const G1_precomputation &rhs_G1, + const G2_precomputation &rhs_G2, + const pb_variable &result, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), + lhs_G1(lhs_G1), + lhs_G2(lhs_G2), + rhs_G1(rhs_G1), + rhs_G2(rhs_G2), + result(result) +{ + ratio.reset(new Fqk_variable(pb, FMT(annotation_prefix, " ratio"))); + compute_ratio.reset(new e_over_e_miller_loop_gadget(pb, lhs_G1, lhs_G2, rhs_G1, rhs_G2, *ratio, FMT(annotation_prefix, " compute_ratio"))); + check_finexp.reset(new final_exp_gadget(pb, *ratio, result, FMT(annotation_prefix, " check_finexp"))); +} + +template +void check_e_equals_e_gadget::generate_r1cs_constraints() +{ + compute_ratio->generate_r1cs_constraints(); + check_finexp->generate_r1cs_constraints(); +} + +template +void check_e_equals_e_gadget::generate_r1cs_witness() +{ + compute_ratio->generate_r1cs_witness(); + check_finexp->generate_r1cs_witness(); +} + +template +check_e_equals_ee_gadget::check_e_equals_ee_gadget(protoboard &pb, + const G1_precomputation &lhs_G1, + const G2_precomputation &lhs_G2, + const G1_precomputation &rhs1_G1, + const G2_precomputation &rhs1_G2, + const G1_precomputation &rhs2_G1, + const G2_precomputation &rhs2_G2, + const pb_variable &result, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), + lhs_G1(lhs_G1), + lhs_G2(lhs_G2), + rhs1_G1(rhs1_G1), + rhs1_G2(rhs1_G2), + rhs2_G1(rhs2_G1), + rhs2_G2(rhs2_G2), + result(result) +{ + ratio.reset(new Fqk_variable(pb, FMT(annotation_prefix, " ratio"))); + compute_ratio.reset(new e_times_e_over_e_miller_loop_gadget(pb, rhs1_G1, rhs1_G2, rhs2_G1, rhs2_G2, lhs_G1, lhs_G2, *ratio, FMT(annotation_prefix, " compute_ratio"))); + check_finexp.reset(new final_exp_gadget(pb, *ratio, result, FMT(annotation_prefix, " check_finexp"))); +} + +template +void check_e_equals_ee_gadget::generate_r1cs_constraints() +{ + compute_ratio->generate_r1cs_constraints(); + check_finexp->generate_r1cs_constraints(); +} + +template +void check_e_equals_ee_gadget::generate_r1cs_witness() +{ + compute_ratio->generate_r1cs_witness(); + check_finexp->generate_r1cs_witness(); +} + +} // libsnark + +#endif // PAIRING_CHECKS_TCC_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/pairing/pairing_params.hpp b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/pairing/pairing_params.hpp new file mode 100644 index 0000000..5338c72 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/pairing/pairing_params.hpp @@ -0,0 +1,116 @@ +/** @file + ***************************************************************************** + + Declaration of selector for the pairing gadget. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef PAIRING_PARAMS_HPP_ +#define PAIRING_PARAMS_HPP_ + +namespace libsnark { + +/** + * The interfaces of pairing gadgets are templatized via the parameter + * ec_ppT. When used, the interfaces must be invoked with + * a particular parameter choice; let 'my_ec_pp' denote this choice. + * + * Moreover, one must provide a template specialization for the class + * pairing_selector (below), containing typedefs for the typenames + * - FieldT + * - FqeT + * - FqkT + * - Fqe_variable_type; + * - Fqe_mul_gadget_type + * - Fqe_mul_by_lc_gadget_type + * - Fqe_sqr_gadget_type + * - Fqk_variable_type + * - Fqk_mul_gadget_type + * - Fqk_special_mul_gadget_type + * - Fqk_sqr_gadget_type + * - other_curve_type + * - e_over_e_miller_loop_gadget_type + * - e_times_e_over_e_miller_loop_gadget_type + * - final_exp_gadget_type + * and also containing a static constant + * - const constexpr bigint pairing_loop_count + * + * For example, if you want to use the types my_Field, my_Fqe, etc, + * then you would do as follows. First declare a new type: + * + * class my_ec_pp; + * + * Second, specialize pairing_selector for the + * case ec_ppT = my_ec_pp, using the above types: + * + * template<> + * class pairing_selector { + * typedef my_Field FieldT; + * typedef my_Fqe FqeT; + * typedef my_Fqk FqkT; + * typedef my_Fqe_variable_type Fqe_variable_type; + * typedef my_Fqe_mul_gadget_type Fqe_mul_gadget_type; + * typedef my_Fqe_mul_by_lc_gadget_type Fqe_mul_by_lc_gadget_type; + * typedef my_Fqe_sqr_gadget_type Fqe_sqr_gadget_type; + * typedef my_Fqk_variable_type Fqk_variable_type; + * typedef my_Fqk_mul_gadget_type Fqk_mul_gadget_type; + * typedef my_Fqk_special_mul_gadget_type Fqk_special_mul_gadget_type; + * typedef my_Fqk_sqr_gadget_type Fqk_sqr_gadget_type; + * typedef my_other_curve_type other_curve_type; + * typedef my_e_over_e_miller_loop_gadget_type e_over_e_miller_loop_gadget_type; + * typedef my_e_times_e_over_e_miller_loop_gadget_type e_times_e_over_e_miller_loop_gadget_type; + * typedef my_final_exp_gadget_type final_exp_gadget_type; + * static const constexpr bigint<...> &pairing_loop_count = ...; + * }; + * + * Having done the above, my_ec_pp can be used as a template parameter. + * + * See mnt_pairing_params.hpp for examples for the case of fixing + * ec_ppT to "MNT4" and "MNT6". + * + */ +template +class pairing_selector; + +/** + * Below are various template aliases (used for convenience). + */ + +template +using FqkT = typename pairing_selector::FqkT; // TODO: better name when stable + +template +using Fqe_variable = typename pairing_selector::Fqe_variable_type; +template +using Fqe_mul_gadget = typename pairing_selector::Fqe_mul_gadget_type; +template +using Fqe_mul_by_lc_gadget = typename pairing_selector::Fqe_mul_by_lc_gadget_type; +template +using Fqe_sqr_gadget = typename pairing_selector::Fqe_sqr_gadget_type; + +template +using Fqk_variable = typename pairing_selector::Fqk_variable_type; +template +using Fqk_mul_gadget = typename pairing_selector::Fqk_mul_gadget_type; +template +using Fqk_special_mul_gadget = typename pairing_selector::Fqk_special_mul_gadget_type; +template +using Fqk_sqr_gadget = typename pairing_selector::Fqk_sqr_gadget_type; + +template +using other_curve = typename pairing_selector::other_curve_type; + +template +using e_over_e_miller_loop_gadget = typename pairing_selector::e_over_e_miller_loop_gadget_type; +template +using e_times_e_over_e_miller_loop_gadget = typename pairing_selector::e_times_e_over_e_miller_loop_gadget_type; +template +using final_exp_gadget = typename pairing_selector::final_exp_gadget_type; + +} // libsnark + +#endif // PAIRING_PARAMS_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/pairing/weierstrass_final_exponentiation.hpp b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/pairing/weierstrass_final_exponentiation.hpp new file mode 100644 index 0000000..c88432e --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/pairing/weierstrass_final_exponentiation.hpp @@ -0,0 +1,110 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for final exponentiation gadgets. + + The gadgets verify final exponentiation for Weiersrass curves with embedding + degrees 4 and 6. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef WEIERSTRASS_FINAL_EXPONENTIATION_HPP_ +#define WEIERSTRASS_FINAL_EXPONENTIATION_HPP_ + +#include +#include "gadgetlib1/gadgets/pairing/mnt_pairing_params.hpp" +#include "gadgetlib1/gadgets/fields/exponentiation_gadget.hpp" + +namespace libsnark { + +/** + * Gadget for final exponentiation with embedding degree 4. + */ +template +class mnt4_final_exp_gadget : public gadget > { +public: + typedef Fr FieldT; + + Fqk_variable el; + std::shared_ptr > one; + std::shared_ptr > el_inv; + std::shared_ptr > el_q_3; + std::shared_ptr > el_q_3_minus_1; + std::shared_ptr > alpha; + std::shared_ptr > beta; + std::shared_ptr > beta_q; + std::shared_ptr > el_inv_q_3; + std::shared_ptr > el_inv_q_3_minus_1; + std::shared_ptr > inv_alpha; + std::shared_ptr > inv_beta; + std::shared_ptr > w1; + std::shared_ptr > w0; + std::shared_ptr > result; + + std::shared_ptr > compute_el_inv; + std::shared_ptr > compute_el_q_3_minus_1; + std::shared_ptr > compute_beta; + std::shared_ptr > compute_el_inv_q_3_minus_1; + std::shared_ptr > compute_inv_beta; + + std::shared_ptr, Fp6_variable, Fp6_mul_gadget, Fp6_cyclotomic_sqr_gadget, mnt6_q_limbs> > compute_w1; + std::shared_ptr, Fp6_variable, Fp6_mul_gadget, Fp6_cyclotomic_sqr_gadget, mnt6_q_limbs> > compute_w0; + std::shared_ptr > compute_result; + + pb_variable result_is_one; + + mnt4_final_exp_gadget(protoboard &pb, + const Fqk_variable &el, + const pb_variable &result_is_one, + const std::string &annotation_prefix); + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +/** + * Gadget for final exponentiation with embedding degree 6. + */ +template +class mnt6_final_exp_gadget : public gadget > { +public: + typedef Fr FieldT; + + Fqk_variable el; + std::shared_ptr > one; + std::shared_ptr > el_inv; + std::shared_ptr > el_q_2; + std::shared_ptr > el_q_2_minus_1; + std::shared_ptr > el_q_3_minus_q; + std::shared_ptr > el_inv_q_2; + std::shared_ptr > el_inv_q_2_minus_1; + std::shared_ptr > w1; + std::shared_ptr > w0; + std::shared_ptr > result; + + std::shared_ptr > compute_el_inv; + std::shared_ptr > compute_el_q_2_minus_1; + std::shared_ptr > compute_el_inv_q_2_minus_1; + + std::shared_ptr, Fp4_variable, Fp4_mul_gadget, Fp4_cyclotomic_sqr_gadget, mnt4_q_limbs> > compute_w1; + std::shared_ptr, Fp4_variable, Fp4_mul_gadget, Fp4_cyclotomic_sqr_gadget, mnt4_q_limbs> > compute_w0; + std::shared_ptr > compute_result; + + pb_variable result_is_one; + + mnt6_final_exp_gadget(protoboard &pb, + const Fqk_variable &el, + const pb_variable &result_is_one, + const std::string &annotation_prefix); + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +} // libsnark + +#include "gadgetlib1/gadgets/pairing/weierstrass_final_exponentiation.tcc" + +#endif // WEIERSTRASS_FINAL_EXPONENTIATION_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/pairing/weierstrass_final_exponentiation.tcc b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/pairing/weierstrass_final_exponentiation.tcc new file mode 100644 index 0000000..3b0d141 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/pairing/weierstrass_final_exponentiation.tcc @@ -0,0 +1,184 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for final exponentiation gadgets. + + See weierstrass_final_exponentiation.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef WEIERSTRASS_FINAL_EXPONENTIATION_TCC_ +#define WEIERSTRASS_FINAL_EXPONENTIATION_TCC_ + +#include "gadgetlib1/gadgets/basic_gadgets.hpp" +#include "gadgetlib1/gadgets/pairing/mnt_pairing_params.hpp" + +namespace libsnark { + +template +mnt4_final_exp_gadget::mnt4_final_exp_gadget(protoboard &pb, + const Fqk_variable &el, + const pb_variable &result_is_one, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), + el(el), + result_is_one(result_is_one) +{ + one.reset(new Fqk_variable(pb, FMT(annotation_prefix, " one"))); + el_inv.reset(new Fqk_variable(pb, FMT(annotation_prefix, " el_inv"))); + el_q_3.reset(new Fqk_variable(el.Frobenius_map(3))); + el_q_3_minus_1.reset(new Fqk_variable(pb, FMT(annotation_prefix, " el_q_3_minus_1"))); + alpha.reset(new Fqk_variable(el_q_3_minus_1->Frobenius_map(1))); + beta.reset(new Fqk_variable(pb, FMT(annotation_prefix, " beta"))); + beta_q.reset(new Fqk_variable(beta->Frobenius_map(1))); + + el_inv_q_3.reset(new Fqk_variable(el_inv->Frobenius_map(3))); + el_inv_q_3_minus_1.reset(new Fqk_variable(pb, FMT(annotation_prefix, " el_inv_q_3_minus_1"))); + inv_alpha.reset(new Fqk_variable(el_inv_q_3_minus_1->Frobenius_map(1))); + inv_beta.reset(new Fqk_variable(pb, FMT(annotation_prefix, " inv_beta"))); + w1.reset(new Fqk_variable(pb, FMT(annotation_prefix, " w1"))); + w0.reset(new Fqk_variable(pb, FMT(annotation_prefix, " w0"))); + result.reset(new Fqk_variable(pb, FMT(annotation_prefix, " result"))); + + compute_el_inv.reset(new Fqk_mul_gadget(pb, el, *el_inv, *one, FMT(annotation_prefix, " compute_el_inv"))); + compute_el_q_3_minus_1.reset(new Fqk_mul_gadget(pb, *el_q_3, *el_inv, *el_q_3_minus_1, FMT(annotation_prefix, " compute_el_q_3_minus_1"))); + compute_beta.reset(new Fqk_mul_gadget(pb, *alpha, *el_q_3_minus_1, *beta, FMT(annotation_prefix, " compute_beta"))); + + compute_el_inv_q_3_minus_1.reset(new Fqk_mul_gadget(pb, *el_inv_q_3, el, *el_inv_q_3_minus_1, FMT(annotation_prefix, " compute_el_inv__q_3_minus_1"))); + compute_inv_beta.reset(new Fqk_mul_gadget(pb, *inv_alpha, *el_inv_q_3_minus_1, *inv_beta, FMT(annotation_prefix, " compute_inv_beta"))); + + compute_w1.reset(new exponentiation_gadget, Fp6_variable, Fp6_mul_gadget, Fp6_cyclotomic_sqr_gadget, mnt6_q_limbs>( + pb, *beta_q, mnt6_final_exponent_last_chunk_w1, *w1, FMT(annotation_prefix, " compute_w1"))); + + compute_w0.reset(new exponentiation_gadget, Fp6_variable, Fp6_mul_gadget, Fp6_cyclotomic_sqr_gadget, mnt6_q_limbs>( + pb, (mnt6_final_exponent_last_chunk_is_w0_neg ? *inv_beta : *beta), mnt6_final_exponent_last_chunk_abs_of_w0, *w0, FMT(annotation_prefix, " compute_w0"))); + + compute_result.reset(new Fqk_mul_gadget(pb, *w1, *w0, *result, FMT(annotation_prefix, " compute_result"))); +} + +template +void mnt4_final_exp_gadget::generate_r1cs_constraints() +{ + one->generate_r1cs_equals_const_constraints(Fqk >::one()); + + compute_el_inv->generate_r1cs_constraints(); + compute_el_q_3_minus_1->generate_r1cs_constraints(); + compute_beta->generate_r1cs_constraints(); + + compute_el_inv_q_3_minus_1->generate_r1cs_constraints(); + compute_inv_beta->generate_r1cs_constraints(); + + compute_w0->generate_r1cs_constraints(); + compute_w1->generate_r1cs_constraints(); + compute_result->generate_r1cs_constraints(); + + generate_boolean_r1cs_constraint(this->pb, result_is_one, FMT(this->annotation_prefix, " result_is_one")); + this->pb.add_r1cs_constraint(r1cs_constraint(result_is_one, 1 - result->c0.c0, 0), " check c0.c0"); + this->pb.add_r1cs_constraint(r1cs_constraint(result_is_one, result->c0.c1, 0), " check c0.c1"); + this->pb.add_r1cs_constraint(r1cs_constraint(result_is_one, result->c0.c2, 0), " check c0.c2"); + this->pb.add_r1cs_constraint(r1cs_constraint(result_is_one, result->c1.c0, 0), " check c1.c0"); + this->pb.add_r1cs_constraint(r1cs_constraint(result_is_one, result->c1.c1, 0), " check c1.c1"); + this->pb.add_r1cs_constraint(r1cs_constraint(result_is_one, result->c1.c2, 0), " check c1.c2"); +} + +template +void mnt4_final_exp_gadget::generate_r1cs_witness() +{ + one->generate_r1cs_witness(Fqk >::one()); + el_inv->generate_r1cs_witness(el.get_element().inverse()); + + compute_el_inv->generate_r1cs_witness(); + el_q_3->evaluate(); + compute_el_q_3_minus_1->generate_r1cs_witness(); + alpha->evaluate(); + compute_beta->generate_r1cs_witness(); + beta_q->evaluate(); + + el_inv_q_3->evaluate(); + compute_el_inv_q_3_minus_1->generate_r1cs_witness(); + inv_alpha->evaluate(); + compute_inv_beta->generate_r1cs_witness(); + + compute_w0->generate_r1cs_witness(); + compute_w1->generate_r1cs_witness(); + compute_result->generate_r1cs_witness(); + + this->pb.val(result_is_one) = (result->get_element() == one->get_element() ? FieldT::one() : FieldT::zero()); +} + +template +mnt6_final_exp_gadget::mnt6_final_exp_gadget(protoboard &pb, + const Fqk_variable &el, + const pb_variable &result_is_one, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), + el(el), + result_is_one(result_is_one) +{ + one.reset(new Fqk_variable(pb, FMT(annotation_prefix, " one"))); + el_inv.reset(new Fqk_variable(pb, FMT(annotation_prefix, " el_inv"))); + el_q_2.reset(new Fqk_variable(el.Frobenius_map(2))); + el_q_2_minus_1.reset(new Fqk_variable(pb, FMT(annotation_prefix, " el_q_2_minus_1"))); + el_q_3_minus_q.reset(new Fqk_variable(el_q_2_minus_1->Frobenius_map(1))); + el_inv_q_2.reset(new Fqk_variable(el_inv->Frobenius_map(2))); + el_inv_q_2_minus_1.reset(new Fqk_variable(pb, FMT(annotation_prefix, " el_inv_q_2_minus_1"))); + w1.reset(new Fqk_variable(pb, FMT(annotation_prefix, " w1"))); + w0.reset(new Fqk_variable(pb, FMT(annotation_prefix, " w0"))); + result.reset(new Fqk_variable(pb, FMT(annotation_prefix, " result"))); + + compute_el_inv.reset(new Fqk_mul_gadget(pb, el, *el_inv, *one, FMT(annotation_prefix, " compute_el_inv"))); + compute_el_q_2_minus_1.reset(new Fqk_mul_gadget(pb, *el_q_2, *el_inv, *el_q_2_minus_1, FMT(annotation_prefix, " compute_el_q_2_minus_1"))); + compute_el_inv_q_2_minus_1.reset(new Fqk_mul_gadget(pb, *el_inv_q_2, el, *el_inv_q_2_minus_1, FMT(annotation_prefix, " compute_el_inv_q_2_minus_1"))); + + compute_w1.reset(new exponentiation_gadget, Fp4_variable, Fp4_mul_gadget, Fp4_cyclotomic_sqr_gadget, mnt4_q_limbs>( + pb, *el_q_3_minus_q, mnt4_final_exponent_last_chunk_w1, *w1, FMT(annotation_prefix, " compute_w1"))); + compute_w0.reset(new exponentiation_gadget, Fp4_variable, Fp4_mul_gadget, Fp4_cyclotomic_sqr_gadget, mnt4_q_limbs>( + pb, (mnt4_final_exponent_last_chunk_is_w0_neg ? *el_inv_q_2_minus_1 : *el_q_2_minus_1), mnt4_final_exponent_last_chunk_abs_of_w0, *w0, FMT(annotation_prefix, " compute_w0"))); + compute_result.reset(new Fqk_mul_gadget(pb, *w1, *w0, *result, FMT(annotation_prefix, " compute_result"))); +} + +template +void mnt6_final_exp_gadget::generate_r1cs_constraints() +{ + one->generate_r1cs_equals_const_constraints(Fqk >::one()); + + compute_el_inv->generate_r1cs_constraints(); + compute_el_q_2_minus_1->generate_r1cs_constraints(); + compute_el_inv_q_2_minus_1->generate_r1cs_constraints(); + compute_w1->generate_r1cs_constraints(); + compute_w0->generate_r1cs_constraints(); + compute_result->generate_r1cs_constraints(); + + generate_boolean_r1cs_constraint(this->pb, result_is_one, FMT(this->annotation_prefix, " result_is_one")); + this->pb.add_r1cs_constraint(r1cs_constraint(result_is_one, 1 - result->c0.c0, 0), " check c0.c0"); + this->pb.add_r1cs_constraint(r1cs_constraint(result_is_one, result->c0.c1, 0), " check c0.c1"); + this->pb.add_r1cs_constraint(r1cs_constraint(result_is_one, result->c1.c0, 0), " check c1.c0"); + this->pb.add_r1cs_constraint(r1cs_constraint(result_is_one, result->c1.c1, 0), " check c1.c0"); +} + +template +void mnt6_final_exp_gadget::generate_r1cs_witness() +{ + one->generate_r1cs_witness(Fqk >::one()); + el_inv->generate_r1cs_witness(el.get_element().inverse()); + + compute_el_inv->generate_r1cs_witness(); + el_q_2->evaluate(); + compute_el_q_2_minus_1->generate_r1cs_witness(); + el_q_3_minus_q->evaluate(); + el_inv_q_2->evaluate(); + compute_el_inv_q_2_minus_1->generate_r1cs_witness(); + compute_w1->generate_r1cs_witness(); + compute_w0->generate_r1cs_witness(); + compute_result->generate_r1cs_witness(); + + this->pb.val(result_is_one) = (result->get_element() == one->get_element() ? FieldT::one() : FieldT::zero()); +} + +} // libsnark + +#endif // WEIERSTRASS_FINAL_EXPONENTIATION_TCC_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/pairing/weierstrass_miller_loop.hpp b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/pairing/weierstrass_miller_loop.hpp new file mode 100644 index 0000000..c2915b3 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/pairing/weierstrass_miller_loop.hpp @@ -0,0 +1,256 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for gadgets for Miller loops. + + The gadgets verify computations of (single or multiple simultaneous) Miller loops. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef WEIERSTRASS_MILLER_LOOP_HPP_ +#define WEIERSTRASS_MILLER_LOOP_HPP_ + +#include +#include "gadgetlib1/gadgets/pairing/pairing_params.hpp" +#include "gadgetlib1/gadgets/pairing/weierstrass_precomputation.hpp" + +namespace libsnark { + +/** + * Gadget for doubling step in the Miller loop. + * + * Technical note: + * + * mnt_Fqk g_RR_at_P = mnt_Fqk(prec_P.PY_twist_squared, + * -prec_P.PX * c.gamma_twist + c.gamma_X - c.old_RY); + * + *(later in Miller loop: f = f.squared() * g_RR_at_P) + * + * Note the slight interface change: this gadget allocates g_RR_at_P inside itself (!) + */ +template +class mnt_miller_loop_dbl_line_eval : public gadget > { +public: + typedef Fr FieldT; + typedef Fqe > FqeT; + typedef Fqk > FqkT; + + G1_precomputation prec_P; + precompute_G2_gadget_coeffs c; + std::shared_ptr > &g_RR_at_P; // reference from outside + + std::shared_ptr > gamma_twist; + std::shared_ptr > g_RR_at_P_c1; + std::shared_ptr > compute_g_RR_at_P_c1; + + mnt_miller_loop_dbl_line_eval(protoboard &pb, + const G1_precomputation &prec_P, + const precompute_G2_gadget_coeffs &c, + std::shared_ptr > &g_RR_at_P, + const std::string &annotation_prefix); + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +/** + * Gadget for addition step in the Miller loop. + * + * Technical note: + * + * mnt_Fqk g_RQ_at_P = mnt_Fqk(prec_P.PY_twist_squared, + * -prec_P.PX * c.gamma_twist + c.gamma_X - prec_Q.QY); + * + * (later in Miller loop: f = f * g_RQ_at_P) + * + * Note the slight interface change: this gadget will allocate g_RQ_at_P inside itself (!) + */ +template +class mnt_miller_loop_add_line_eval : public gadget > { +public: + typedef Fr FieldT; + typedef Fqe > FqeT; + typedef Fqk > FqkT; + + bool invert_Q; + G1_precomputation prec_P; + precompute_G2_gadget_coeffs c; + G2_variable Q; + std::shared_ptr > &g_RQ_at_P; // reference from outside + + std::shared_ptr > gamma_twist; + std::shared_ptr > g_RQ_at_P_c1; + std::shared_ptr > compute_g_RQ_at_P_c1; + + mnt_miller_loop_add_line_eval(protoboard &pb, + const bool invert_Q, + const G1_precomputation &prec_P, + const precompute_G2_gadget_coeffs &c, + const G2_variable &Q, + std::shared_ptr > &g_RQ_at_P, + const std::string &annotation_prefix); + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +/** + * Gadget for verifying a single Miller loop. + */ +template +class mnt_miller_loop_gadget : public gadget > { +public: + typedef Fr FieldT; + typedef Fqe > FqeT; + typedef Fqk > FqkT; + + std::vector > > g_RR_at_Ps; + std::vector > > g_RQ_at_Ps; + std::vector > > fs; + + std::vector > > addition_steps; + std::vector > > doubling_steps; + + std::vector > > dbl_muls; + std::vector > > dbl_sqrs; + std::vector > > add_muls; + + size_t f_count; + size_t add_count; + size_t dbl_count; + + G1_precomputation prec_P; + G2_precomputation prec_Q; + Fqk_variable result; + + mnt_miller_loop_gadget(protoboard &pb, + const G1_precomputation &prec_P, + const G2_precomputation &prec_Q, + const Fqk_variable &result, + const std::string &annotation_prefix); + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +template +void test_mnt_miller_loop(const std::string &annotation); + +/** + * Gadget for verifying a double Miller loop (where the second is inverted). + */ +template +class mnt_e_over_e_miller_loop_gadget : public gadget > { +public: + typedef Fr FieldT; + typedef Fqe > FqeT; + typedef Fqk > FqkT; + + std::vector > > g_RR_at_P1s; + std::vector > > g_RQ_at_P1s; + std::vector > > g_RR_at_P2s; + std::vector > > g_RQ_at_P2s; + std::vector > > fs; + + std::vector > > addition_steps1; + std::vector > > doubling_steps1; + std::vector > > addition_steps2; + std::vector > > doubling_steps2; + + std::vector > > dbl_sqrs; + std::vector > > dbl_muls1; + std::vector > > add_muls1; + std::vector > > dbl_muls2; + std::vector > > add_muls2; + + size_t f_count; + size_t add_count; + size_t dbl_count; + + G1_precomputation prec_P1; + G2_precomputation prec_Q1; + G1_precomputation prec_P2; + G2_precomputation prec_Q2; + Fqk_variable result; + + mnt_e_over_e_miller_loop_gadget(protoboard &pb, + const G1_precomputation &prec_P1, + const G2_precomputation &prec_Q1, + const G1_precomputation &prec_P2, + const G2_precomputation &prec_Q2, + const Fqk_variable &result, + const std::string &annotation_prefix); + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +template +void test_mnt_e_over_e_miller_loop(const std::string &annotation); + +/** + * Gadget for verifying a triple Miller loop (where the third is inverted). + */ +template +class mnt_e_times_e_over_e_miller_loop_gadget : public gadget > { +public: + typedef Fr FieldT; + typedef Fqe > FqeT; + typedef Fqk > FqkT; + + std::vector > > g_RR_at_P1s; + std::vector > > g_RQ_at_P1s; + std::vector > > g_RR_at_P2s; + std::vector > > g_RQ_at_P2s; + std::vector > > g_RR_at_P3s; + std::vector > > g_RQ_at_P3s; + std::vector > > fs; + + std::vector > > addition_steps1; + std::vector > > doubling_steps1; + std::vector > > addition_steps2; + std::vector > > doubling_steps2; + std::vector > > addition_steps3; + std::vector > > doubling_steps3; + + std::vector > > dbl_sqrs; + std::vector > > dbl_muls1; + std::vector > > add_muls1; + std::vector > > dbl_muls2; + std::vector > > add_muls2; + std::vector > > dbl_muls3; + std::vector > > add_muls3; + + size_t f_count; + size_t add_count; + size_t dbl_count; + + G1_precomputation prec_P1; + G2_precomputation prec_Q1; + G1_precomputation prec_P2; + G2_precomputation prec_Q2; + G1_precomputation prec_P3; + G2_precomputation prec_Q3; + Fqk_variable result; + + mnt_e_times_e_over_e_miller_loop_gadget(protoboard &pb, + const G1_precomputation &prec_P1, + const G2_precomputation &prec_Q1, + const G1_precomputation &prec_P2, + const G2_precomputation &prec_Q2, + const G1_precomputation &prec_P3, + const G2_precomputation &prec_Q3, + const Fqk_variable &result, + const std::string &annotation_prefix); + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +template +void test_mnt_e_times_e_over_e_miller_loop(const std::string &annotation); + +} // libsnark + +#include "gadgetlib1/gadgets/pairing/weierstrass_miller_loop.tcc" + +#endif // WEIERSTRASS_MILLER_LOOP_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/pairing/weierstrass_miller_loop.tcc b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/pairing/weierstrass_miller_loop.tcc new file mode 100644 index 0000000..45afab3 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/pairing/weierstrass_miller_loop.tcc @@ -0,0 +1,900 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for gadgets for Miller loops. + + See weierstrass_miller_loop.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef WEIERSTRASS_MILLER_LOOP_TCC_ +#define WEIERSTRASS_MILLER_LOOP_TCC_ + +#include "algebra/scalar_multiplication/wnaf.hpp" +#include "gadgetlib1/constraint_profiling.hpp" +#include "gadgetlib1/gadgets/basic_gadgets.hpp" + +namespace libsnark { + +/* + performs + + mnt_Fqk g_RR_at_P = mnt_Fqk(prec_P.PY_twist_squared, + -prec_P.PX * c.gamma_twist + c.gamma_X - c.old_RY); + + (later in Miller loop: f = f.squared() * g_RR_at_P) +*/ + +/* Note the slight interface change: this gadget will allocate g_RR_at_P inside itself (!) */ +template +mnt_miller_loop_dbl_line_eval::mnt_miller_loop_dbl_line_eval(protoboard &pb, + const G1_precomputation &prec_P, + const precompute_G2_gadget_coeffs &c, + std::shared_ptr > &g_RR_at_P, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), prec_P(prec_P), c(c), g_RR_at_P(g_RR_at_P) +{ + gamma_twist.reset(new Fqe_variable(c.gamma->mul_by_X())); + // prec_P.PX * c.gamma_twist = c.gamma_X - c.old_RY - g_RR_at_P_c1 + if (gamma_twist->is_constant()) + { + gamma_twist->evaluate(); + const FqeT gamma_twist_const = gamma_twist->get_element(); + g_RR_at_P_c1.reset(new Fqe_variable(Fqe_variable(this->pb, -gamma_twist_const, prec_P.P->X, FMT(annotation_prefix, " tmp")) + + *(c.gamma_X) + *(c.RY) * (-FieldT::one()))); + } + else if (prec_P.P->X.is_constant()) + { + prec_P.P->X.evaluate(pb); + const FieldT P_X_const = prec_P.P->X.constant_term(); + g_RR_at_P_c1.reset(new Fqe_variable(*gamma_twist * (-P_X_const) + *(c.gamma_X) + *(c.RY) * (-FieldT::one()))); + } + else + { + g_RR_at_P_c1.reset(new Fqe_variable(pb, FMT(annotation_prefix, " g_RR_at_P_c1"))); + compute_g_RR_at_P_c1.reset(new Fqe_mul_by_lc_gadget(pb, *gamma_twist, prec_P.P->X, + *(c.gamma_X) + *(c.RY) * (-FieldT::one()) + (*g_RR_at_P_c1) * (-FieldT::one()), + FMT(annotation_prefix, " compute_g_RR_at_P_c1"))); + } + g_RR_at_P.reset(new Fqk_variable(pb, *(prec_P.PY_twist_squared), *g_RR_at_P_c1, FMT(annotation_prefix, " g_RR_at_P"))); +} + +template +void mnt_miller_loop_dbl_line_eval::generate_r1cs_constraints() +{ + if (!gamma_twist->is_constant() && !prec_P.P->X.is_constant()) + { + compute_g_RR_at_P_c1->generate_r1cs_constraints(); + } +} + +template +void mnt_miller_loop_dbl_line_eval::generate_r1cs_witness() +{ + gamma_twist->evaluate(); + const FqeT gamma_twist_val = gamma_twist->get_element(); + const FieldT PX_val = this->pb.lc_val(prec_P.P->X); + const FqeT gamma_X_val = c.gamma_X->get_element(); + const FqeT RY_val = c.RY->get_element(); + const FqeT g_RR_at_P_c1_val = -PX_val * gamma_twist_val + gamma_X_val - RY_val; + g_RR_at_P_c1->generate_r1cs_witness(g_RR_at_P_c1_val); + + if (!gamma_twist->is_constant() && !prec_P.P->X.is_constant()) + { + compute_g_RR_at_P_c1->generate_r1cs_witness(); + } + g_RR_at_P->evaluate(); +} + +/* + performs + mnt_Fqk g_RQ_at_P = mnt_Fqk(prec_P.PY_twist_squared, + -prec_P.PX * c.gamma_twist + c.gamma_X - prec_Q.QY); + + (later in Miller loop: f = f * g_RQ_at_P) + + If invert_Q is set to true: use -QY in place of QY everywhere above. +*/ + +/* Note the slight interface change: this gadget will allocate g_RQ_at_P inside itself (!) */ +template +mnt_miller_loop_add_line_eval::mnt_miller_loop_add_line_eval(protoboard &pb, + const bool invert_Q, + const G1_precomputation &prec_P, + const precompute_G2_gadget_coeffs &c, + const G2_variable &Q, + std::shared_ptr > &g_RQ_at_P, + const std::string &annotation_prefix) : +gadget(pb, annotation_prefix), invert_Q(invert_Q), prec_P(prec_P), c(c), Q(Q), g_RQ_at_P(g_RQ_at_P) +{ + gamma_twist.reset(new Fqe_variable(c.gamma->mul_by_X())); + // prec_P.PX * c.gamma_twist = c.gamma_X - prec_Q.QY - g_RQ_at_P_c1 + if (gamma_twist->is_constant()) + { + gamma_twist->evaluate(); + const FqeT gamma_twist_const = gamma_twist->get_element(); + g_RQ_at_P_c1.reset(new Fqe_variable(Fqe_variable(this->pb, -gamma_twist_const, prec_P.P->X, FMT(annotation_prefix, " tmp")) + + *(c.gamma_X) + *(Q.Y) * (!invert_Q ? -FieldT::one() : FieldT::one()))); + } + else if (prec_P.P->X.is_constant()) + { + prec_P.P->X.evaluate(pb); + const FieldT P_X_const = prec_P.P->X.constant_term(); + g_RQ_at_P_c1.reset(new Fqe_variable(*gamma_twist * (-P_X_const) + *(c.gamma_X) + *(Q.Y) * (!invert_Q ? -FieldT::one() : FieldT::one()))); + } + else + { + g_RQ_at_P_c1.reset(new Fqe_variable(pb, FMT(annotation_prefix, " g_RQ_at_Q_c1"))); + compute_g_RQ_at_P_c1.reset(new Fqe_mul_by_lc_gadget(pb, *gamma_twist, prec_P.P->X, + *(c.gamma_X) + *(Q.Y) * (!invert_Q ? -FieldT::one() : FieldT::one()) + (*g_RQ_at_P_c1) * (-FieldT::one()), + FMT(annotation_prefix, " compute_g_RQ_at_P_c1"))); + } + g_RQ_at_P.reset(new Fqk_variable(pb, *(prec_P.PY_twist_squared), *g_RQ_at_P_c1, FMT(annotation_prefix, " g_RQ_at_P"))); +} + +template +void mnt_miller_loop_add_line_eval::generate_r1cs_constraints() +{ + if (!gamma_twist->is_constant() && !prec_P.P->X.is_constant()) + { + compute_g_RQ_at_P_c1->generate_r1cs_constraints(); + } +} + +template +void mnt_miller_loop_add_line_eval::generate_r1cs_witness() +{ + gamma_twist->evaluate(); + const FqeT gamma_twist_val = gamma_twist->get_element(); + const FieldT PX_val = this->pb.lc_val(prec_P.P->X); + const FqeT gamma_X_val = c.gamma_X->get_element(); + const FqeT QY_val = Q.Y->get_element(); + const FqeT g_RQ_at_P_c1_val = -PX_val * gamma_twist_val + gamma_X_val + (!invert_Q ? -QY_val : QY_val); + g_RQ_at_P_c1->generate_r1cs_witness(g_RQ_at_P_c1_val); + + if (!gamma_twist->is_constant() && !prec_P.P->X.is_constant()) + { + compute_g_RQ_at_P_c1->generate_r1cs_witness(); + } + g_RQ_at_P->evaluate(); +} + +template +mnt_miller_loop_gadget::mnt_miller_loop_gadget(protoboard &pb, + const G1_precomputation &prec_P, + const G2_precomputation &prec_Q, + const Fqk_variable &result, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), prec_P(prec_P), prec_Q(prec_Q), result(result) +{ + const auto &loop_count = pairing_selector::pairing_loop_count; + + f_count = add_count = dbl_count = 0; + + bool found_nonzero = false; + std::vector NAF = find_wnaf(1, loop_count); + for (long i = NAF.size()-1; i >= 0; --i) + { + if (!found_nonzero) + { + /* this skips the MSB itself */ + found_nonzero |= (NAF[i] != 0); + continue; + } + + ++dbl_count; + f_count += 2; + + if (NAF[i] != 0) + { + ++add_count; + f_count += 1; + } + } + + fs.resize(f_count); + doubling_steps.resize(dbl_count); + addition_steps.resize(add_count); + g_RR_at_Ps.resize(dbl_count); + g_RQ_at_Ps.resize(add_count); + + for (size_t i = 0; i < f_count; ++i) + { + fs[i].reset(new Fqk_variable(pb, FMT(annotation_prefix, " fs_%zu", i))); + } + + dbl_sqrs.resize(dbl_count); + dbl_muls.resize(dbl_count); + add_muls.resize(add_count); + + size_t add_id = 0; + size_t dbl_id = 0; + size_t f_id = 0; + size_t prec_id = 0; + + found_nonzero = false; + for (long i = NAF.size()-1; i >= 0; --i) + { + if (!found_nonzero) + { + /* this skips the MSB itself */ + found_nonzero |= (NAF[i] != 0); + continue; + } + + doubling_steps[dbl_id].reset(new mnt_miller_loop_dbl_line_eval(pb, + prec_P, *prec_Q.coeffs[prec_id], + g_RR_at_Ps[dbl_id], + FMT(annotation_prefix, " doubling_steps_%zu", dbl_id))); + ++prec_id; + dbl_sqrs[dbl_id].reset(new Fqk_sqr_gadget(pb, *fs[f_id], *fs[f_id+1], FMT(annotation_prefix, " dbl_sqrs_%zu", dbl_id))); + ++f_id; + dbl_muls[dbl_id].reset(new Fqk_special_mul_gadget(pb, *fs[f_id], *g_RR_at_Ps[dbl_id], (f_id + 1 == f_count ? result : *fs[f_id+1]), FMT(annotation_prefix, " dbl_muls_%zu", dbl_id))); + ++f_id; + ++dbl_id; + + if (NAF[i] != 0) + { + addition_steps[add_id].reset(new mnt_miller_loop_add_line_eval(pb, + NAF[i] < 0, + prec_P, *prec_Q.coeffs[prec_id], *prec_Q.Q, + g_RQ_at_Ps[add_id], + FMT(annotation_prefix, " addition_steps_%zu", add_id))); + ++prec_id; + add_muls[add_id].reset(new Fqk_special_mul_gadget(pb, *fs[f_id], *g_RQ_at_Ps[add_id], (f_id + 1 == f_count ? result : *fs[f_id+1]), FMT(annotation_prefix, " add_muls_%zu", add_id))); + ++f_id; + ++add_id; + } + } +} + +template +void mnt_miller_loop_gadget::generate_r1cs_constraints() +{ + fs[0]->generate_r1cs_equals_const_constraints(FqkT::one()); + + for (size_t i = 0; i < dbl_count; ++i) + { + doubling_steps[i]->generate_r1cs_constraints(); + dbl_sqrs[i]->generate_r1cs_constraints(); + dbl_muls[i]->generate_r1cs_constraints(); + } + + for (size_t i = 0; i < add_count; ++i) + { + addition_steps[i]->generate_r1cs_constraints(); + add_muls[i]->generate_r1cs_constraints(); + } +} + +template +void mnt_miller_loop_gadget::generate_r1cs_witness() +{ + fs[0]->generate_r1cs_witness(FqkT::one()); + + size_t add_id = 0; + size_t dbl_id = 0; + + const auto &loop_count = pairing_selector::pairing_loop_count; + + bool found_nonzero = false; + std::vector NAF = find_wnaf(1, loop_count); + for (long i = NAF.size()-1; i >= 0; --i) + { + if (!found_nonzero) + { + /* this skips the MSB itself */ + found_nonzero |= (NAF[i] != 0); + continue; + } + + doubling_steps[dbl_id]->generate_r1cs_witness(); + dbl_sqrs[dbl_id]->generate_r1cs_witness(); + dbl_muls[dbl_id]->generate_r1cs_witness(); + ++dbl_id; + + if (NAF[i] != 0) + { + addition_steps[add_id]->generate_r1cs_witness(); + add_muls[add_id]->generate_r1cs_witness(); + ++add_id; + } + } +} + +template +void test_mnt_miller_loop(const std::string &annotation) +{ + protoboard > pb; + G1 > P_val = Fr >::random_element() * G1 >::one(); + G2 > Q_val = Fr >::random_element() * G2 >::one(); + + G1_variable P(pb, "P"); + G2_variable Q(pb, "Q"); + + G1_precomputation prec_P; + G2_precomputation prec_Q; + + precompute_G1_gadget compute_prec_P(pb, P, prec_P, "prec_P"); + precompute_G2_gadget compute_prec_Q(pb, Q, prec_Q, "prec_Q"); + + Fqk_variable result(pb, "result"); + mnt_miller_loop_gadget miller(pb, prec_P, prec_Q, result, "miller"); + + PROFILE_CONSTRAINTS(pb, "precompute P") + { + compute_prec_P.generate_r1cs_constraints(); + } + PROFILE_CONSTRAINTS(pb, "precompute Q") + { + compute_prec_Q.generate_r1cs_constraints(); + } + PROFILE_CONSTRAINTS(pb, "Miller loop") + { + miller.generate_r1cs_constraints(); + } + PRINT_CONSTRAINT_PROFILING(); + + P.generate_r1cs_witness(P_val); + compute_prec_P.generate_r1cs_witness(); + Q.generate_r1cs_witness(Q_val); + compute_prec_Q.generate_r1cs_witness(); + miller.generate_r1cs_witness(); + assert(pb.is_satisfied()); + + affine_ate_G1_precomp > native_prec_P = other_curve::affine_ate_precompute_G1(P_val); + affine_ate_G2_precomp > native_prec_Q = other_curve::affine_ate_precompute_G2(Q_val); + Fqk > native_result = other_curve::affine_ate_miller_loop(native_prec_P, native_prec_Q); + + assert(result.get_element() == native_result); + printf("number of constraints for Miller loop (Fr is %s) = %zu\n", annotation.c_str(), pb.num_constraints()); +} + +template +mnt_e_over_e_miller_loop_gadget::mnt_e_over_e_miller_loop_gadget(protoboard &pb, + const G1_precomputation &prec_P1, + const G2_precomputation &prec_Q1, + const G1_precomputation &prec_P2, + const G2_precomputation &prec_Q2, + const Fqk_variable &result, + const std::string &annotation_prefix) : +gadget(pb, annotation_prefix), prec_P1(prec_P1), prec_Q1(prec_Q1), prec_P2(prec_P2), prec_Q2(prec_Q2), result(result) +{ + const auto &loop_count = pairing_selector::pairing_loop_count; + + f_count = add_count = dbl_count = 0; + + bool found_nonzero = false; + std::vector NAF = find_wnaf(1, loop_count); + for (long i = NAF.size()-1; i >= 0; --i) + { + if (!found_nonzero) + { + /* this skips the MSB itself */ + found_nonzero |= (NAF[i] != 0); + continue; + } + + ++dbl_count; + f_count += 3; + + if (NAF[i] != 0) + { + ++add_count; + f_count += 2; + } + } + + fs.resize(f_count); + doubling_steps1.resize(dbl_count); + addition_steps1.resize(add_count); + doubling_steps2.resize(dbl_count); + addition_steps2.resize(add_count); + g_RR_at_P1s.resize(dbl_count); + g_RQ_at_P1s.resize(add_count); + g_RR_at_P2s.resize(dbl_count); + g_RQ_at_P2s.resize(add_count); + + for (size_t i = 0; i < f_count; ++i) + { + fs[i].reset(new Fqk_variable(pb, FMT(annotation_prefix, " fs_%zu", i))); + } + + dbl_sqrs.resize(dbl_count); + dbl_muls1.resize(dbl_count); + add_muls1.resize(add_count); + dbl_muls2.resize(dbl_count); + add_muls2.resize(add_count); + + size_t add_id = 0; + size_t dbl_id = 0; + size_t f_id = 0; + size_t prec_id = 0; + + found_nonzero = false; + for (long i = NAF.size()-1; i >= 0; --i) + { + if (!found_nonzero) + { + /* this skips the MSB itself */ + found_nonzero |= (NAF[i] != 0); + continue; + } + + doubling_steps1[dbl_id].reset(new mnt_miller_loop_dbl_line_eval(pb, + prec_P1, *prec_Q1.coeffs[prec_id], + g_RR_at_P1s[dbl_id], + FMT(annotation_prefix, " doubling_steps1_%zu", dbl_id))); + doubling_steps2[dbl_id].reset(new mnt_miller_loop_dbl_line_eval(pb, + prec_P2, *prec_Q2.coeffs[prec_id], + g_RR_at_P2s[dbl_id], + FMT(annotation_prefix, " doubling_steps2_%zu", dbl_id))); + ++prec_id; + + dbl_sqrs[dbl_id].reset(new Fqk_sqr_gadget(pb, *fs[f_id], *fs[f_id+1], FMT(annotation_prefix, " dbl_sqrs_%zu", dbl_id))); + ++f_id; + dbl_muls1[dbl_id].reset(new Fqk_special_mul_gadget(pb, *fs[f_id], *g_RR_at_P1s[dbl_id], *fs[f_id+1], FMT(annotation_prefix, " dbl_mul1s_%zu", dbl_id))); + ++f_id; + dbl_muls2[dbl_id].reset(new Fqk_special_mul_gadget(pb, (f_id + 1 == f_count ? result : *fs[f_id+1]), *g_RR_at_P2s[dbl_id], *fs[f_id], FMT(annotation_prefix, " dbl_mul2s_%zu", dbl_id))); + ++f_id; + ++dbl_id; + + if (NAF[i] != 0) + { + addition_steps1[add_id].reset(new mnt_miller_loop_add_line_eval(pb, + NAF[i] < 0, + prec_P1, *prec_Q1.coeffs[prec_id], *prec_Q1.Q, + g_RQ_at_P1s[add_id], + FMT(annotation_prefix, " addition_steps1_%zu", add_id))); + addition_steps2[add_id].reset(new mnt_miller_loop_add_line_eval(pb, + NAF[i] < 0, + prec_P2, *prec_Q2.coeffs[prec_id], *prec_Q2.Q, + g_RQ_at_P2s[add_id], + FMT(annotation_prefix, " addition_steps2_%zu", add_id))); + ++prec_id; + add_muls1[add_id].reset(new Fqk_special_mul_gadget(pb, *fs[f_id], *g_RQ_at_P1s[add_id], *fs[f_id+1], FMT(annotation_prefix, " add_mul1s_%zu", add_id))); + ++f_id; + add_muls2[add_id].reset(new Fqk_special_mul_gadget(pb, (f_id + 1 == f_count ? result : *fs[f_id+1]), *g_RQ_at_P2s[add_id], *fs[f_id], FMT(annotation_prefix, " add_mul2s_%zu", add_id))); + ++f_id; + ++add_id; + } + } +} + +template +void mnt_e_over_e_miller_loop_gadget::generate_r1cs_constraints() +{ + fs[0]->generate_r1cs_equals_const_constraints(FqkT::one()); + + for (size_t i = 0; i < dbl_count; ++i) + { + doubling_steps1[i]->generate_r1cs_constraints(); + doubling_steps2[i]->generate_r1cs_constraints(); + dbl_sqrs[i]->generate_r1cs_constraints(); + dbl_muls1[i]->generate_r1cs_constraints(); + dbl_muls2[i]->generate_r1cs_constraints(); + } + + for (size_t i = 0; i < add_count; ++i) + { + addition_steps1[i]->generate_r1cs_constraints(); + addition_steps2[i]->generate_r1cs_constraints(); + add_muls1[i]->generate_r1cs_constraints(); + add_muls2[i]->generate_r1cs_constraints(); + } +} + +template +void mnt_e_over_e_miller_loop_gadget::generate_r1cs_witness() +{ + fs[0]->generate_r1cs_witness(FqkT::one()); + + size_t add_id = 0; + size_t dbl_id = 0; + size_t f_id = 0; + + const auto &loop_count = pairing_selector::pairing_loop_count; + + bool found_nonzero = false; + std::vector NAF = find_wnaf(1, loop_count); + for (long i = NAF.size()-1; i >= 0; --i) + { + if (!found_nonzero) + { + /* this skips the MSB itself */ + found_nonzero |= (NAF[i] != 0); + continue; + } + + doubling_steps1[dbl_id]->generate_r1cs_witness(); + doubling_steps2[dbl_id]->generate_r1cs_witness(); + dbl_sqrs[dbl_id]->generate_r1cs_witness(); + ++f_id; + dbl_muls1[dbl_id]->generate_r1cs_witness(); + ++f_id; + (f_id+1 == f_count ? result : *fs[f_id+1]).generate_r1cs_witness(fs[f_id]->get_element() * g_RR_at_P2s[dbl_id]->get_element().inverse()); + dbl_muls2[dbl_id]->generate_r1cs_witness(); + ++f_id; + ++dbl_id; + + if (NAF[i] != 0) + { + addition_steps1[add_id]->generate_r1cs_witness(); + addition_steps2[add_id]->generate_r1cs_witness(); + add_muls1[add_id]->generate_r1cs_witness(); + ++f_id; + (f_id+1 == f_count ? result : *fs[f_id+1]).generate_r1cs_witness(fs[f_id]->get_element() * g_RQ_at_P2s[add_id]->get_element().inverse()); + add_muls2[add_id]->generate_r1cs_witness(); + ++f_id; + ++add_id; + } + } +} + +template +void test_mnt_e_over_e_miller_loop(const std::string &annotation) +{ + protoboard > pb; + G1 > P1_val = Fr >::random_element() * G1 >::one(); + G2 > Q1_val = Fr >::random_element() * G2 >::one(); + + G1 > P2_val = Fr >::random_element() * G1 >::one(); + G2 > Q2_val = Fr >::random_element() * G2 >::one(); + + G1_variable P1(pb, "P1"); + G2_variable Q1(pb, "Q1"); + G1_variable P2(pb, "P2"); + G2_variable Q2(pb, "Q2"); + + G1_precomputation prec_P1; + precompute_G1_gadget compute_prec_P1(pb, P1, prec_P1, "compute_prec_P1"); + G1_precomputation prec_P2; + precompute_G1_gadget compute_prec_P2(pb, P2, prec_P2, "compute_prec_P2"); + G2_precomputation prec_Q1; + precompute_G2_gadget compute_prec_Q1(pb, Q1, prec_Q1, "compute_prec_Q1"); + G2_precomputation prec_Q2; + precompute_G2_gadget compute_prec_Q2(pb, Q2, prec_Q2, "compute_prec_Q2"); + + Fqk_variable result(pb, "result"); + mnt_e_over_e_miller_loop_gadget miller(pb, prec_P1, prec_Q1, prec_P2, prec_Q2, result, "miller"); + + PROFILE_CONSTRAINTS(pb, "precompute P") + { + compute_prec_P1.generate_r1cs_constraints(); + compute_prec_P2.generate_r1cs_constraints(); + } + PROFILE_CONSTRAINTS(pb, "precompute Q") + { + compute_prec_Q1.generate_r1cs_constraints(); + compute_prec_Q2.generate_r1cs_constraints(); + } + PROFILE_CONSTRAINTS(pb, "Miller loop") + { + miller.generate_r1cs_constraints(); + } + PRINT_CONSTRAINT_PROFILING(); + + P1.generate_r1cs_witness(P1_val); + compute_prec_P1.generate_r1cs_witness(); + Q1.generate_r1cs_witness(Q1_val); + compute_prec_Q1.generate_r1cs_witness(); + P2.generate_r1cs_witness(P2_val); + compute_prec_P2.generate_r1cs_witness(); + Q2.generate_r1cs_witness(Q2_val); + compute_prec_Q2.generate_r1cs_witness(); + miller.generate_r1cs_witness(); + assert(pb.is_satisfied()); + + affine_ate_G1_precomp > native_prec_P1 = other_curve::affine_ate_precompute_G1(P1_val); + affine_ate_G2_precomp > native_prec_Q1 = other_curve::affine_ate_precompute_G2(Q1_val); + affine_ate_G1_precomp > native_prec_P2 = other_curve::affine_ate_precompute_G1(P2_val); + affine_ate_G2_precomp > native_prec_Q2 = other_curve::affine_ate_precompute_G2(Q2_val); + Fqk > native_result = (other_curve::affine_ate_miller_loop(native_prec_P1, native_prec_Q1) * + other_curve::affine_ate_miller_loop(native_prec_P2, native_prec_Q2).inverse()); + + assert(result.get_element() == native_result); + printf("number of constraints for e over e Miller loop (Fr is %s) = %zu\n", annotation.c_str(), pb.num_constraints()); +} + +template +mnt_e_times_e_over_e_miller_loop_gadget::mnt_e_times_e_over_e_miller_loop_gadget(protoboard &pb, + const G1_precomputation &prec_P1, + const G2_precomputation &prec_Q1, + const G1_precomputation &prec_P2, + const G2_precomputation &prec_Q2, + const G1_precomputation &prec_P3, + const G2_precomputation &prec_Q3, + const Fqk_variable &result, + const std::string &annotation_prefix) : +gadget(pb, annotation_prefix), prec_P1(prec_P1), prec_Q1(prec_Q1), prec_P2(prec_P2), prec_Q2(prec_Q2), prec_P3(prec_P3), prec_Q3(prec_Q3), result(result) +{ + const auto &loop_count = pairing_selector::pairing_loop_count; + + f_count = add_count = dbl_count = 0; + + bool found_nonzero = false; + std::vector NAF = find_wnaf(1, loop_count); + for (long i = NAF.size()-1; i >= 0; --i) + { + if (!found_nonzero) + { + /* this skips the MSB itself */ + found_nonzero |= (NAF[i] != 0); + continue; + } + + ++dbl_count; + f_count += 4; + + if (NAF[i] != 0) + { + ++add_count; + f_count += 3; + } + } + + fs.resize(f_count); + doubling_steps1.resize(dbl_count); + addition_steps1.resize(add_count); + doubling_steps2.resize(dbl_count); + addition_steps2.resize(add_count); + doubling_steps3.resize(dbl_count); + addition_steps3.resize(add_count); + g_RR_at_P1s.resize(dbl_count); + g_RQ_at_P1s.resize(add_count); + g_RR_at_P2s.resize(dbl_count); + g_RQ_at_P2s.resize(add_count); + g_RR_at_P3s.resize(dbl_count); + g_RQ_at_P3s.resize(add_count); + + for (size_t i = 0; i < f_count; ++i) + { + fs[i].reset(new Fqk_variable(pb, FMT(annotation_prefix, " fs_%zu", i))); + } + + dbl_sqrs.resize(dbl_count); + dbl_muls1.resize(dbl_count); + add_muls1.resize(add_count); + dbl_muls2.resize(dbl_count); + add_muls2.resize(add_count); + dbl_muls3.resize(dbl_count); + add_muls3.resize(add_count); + + size_t add_id = 0; + size_t dbl_id = 0; + size_t f_id = 0; + size_t prec_id = 0; + + found_nonzero = false; + for (long i = NAF.size()-1; i >= 0; --i) + { + if (!found_nonzero) + { + /* this skips the MSB itself */ + found_nonzero |= (NAF[i] != 0); + continue; + } + + doubling_steps1[dbl_id].reset(new mnt_miller_loop_dbl_line_eval(pb, + prec_P1, *prec_Q1.coeffs[prec_id], + g_RR_at_P1s[dbl_id], + FMT(annotation_prefix, " doubling_steps1_%zu", dbl_id))); + doubling_steps2[dbl_id].reset(new mnt_miller_loop_dbl_line_eval(pb, + prec_P2, *prec_Q2.coeffs[prec_id], + g_RR_at_P2s[dbl_id], + FMT(annotation_prefix, " doubling_steps2_%zu", dbl_id))); + doubling_steps3[dbl_id].reset(new mnt_miller_loop_dbl_line_eval(pb, + prec_P3, *prec_Q3.coeffs[prec_id], + g_RR_at_P3s[dbl_id], + FMT(annotation_prefix, " doubling_steps3_%zu", dbl_id))); + ++prec_id; + + dbl_sqrs[dbl_id].reset(new Fqk_sqr_gadget(pb, *fs[f_id], *fs[f_id+1], FMT(annotation_prefix, " dbl_sqrs_%zu", dbl_id))); + ++f_id; + dbl_muls1[dbl_id].reset(new Fqk_special_mul_gadget(pb, *fs[f_id], *g_RR_at_P1s[dbl_id], *fs[f_id+1], FMT(annotation_prefix, " dbl_muls1_%zu", dbl_id))); + ++f_id; + dbl_muls2[dbl_id].reset(new Fqk_special_mul_gadget(pb, *fs[f_id], *g_RR_at_P2s[dbl_id], *fs[f_id+1], FMT(annotation_prefix, " dbl_muls2_%zu", dbl_id))); + ++f_id; + dbl_muls3[dbl_id].reset(new Fqk_special_mul_gadget(pb, (f_id + 1 == f_count ? result : *fs[f_id+1]), *g_RR_at_P3s[dbl_id], *fs[f_id], FMT(annotation_prefix, " dbl_muls3_%zu", dbl_id))); + ++f_id; + ++dbl_id; + + if (NAF[i] != 0) + { + addition_steps1[add_id].reset(new mnt_miller_loop_add_line_eval(pb, + NAF[i] < 0, + prec_P1, *prec_Q1.coeffs[prec_id], *prec_Q1.Q, + g_RQ_at_P1s[add_id], + FMT(annotation_prefix, " addition_steps1_%zu", add_id))); + addition_steps2[add_id].reset(new mnt_miller_loop_add_line_eval(pb, + NAF[i] < 0, + prec_P2, *prec_Q2.coeffs[prec_id], *prec_Q2.Q, + g_RQ_at_P2s[add_id], + FMT(annotation_prefix, " addition_steps2_%zu", add_id))); + addition_steps3[add_id].reset(new mnt_miller_loop_add_line_eval(pb, + NAF[i] < 0, + prec_P3, *prec_Q3.coeffs[prec_id], *prec_Q3.Q, + g_RQ_at_P3s[add_id], + FMT(annotation_prefix, " addition_steps3_%zu", add_id))); + ++prec_id; + add_muls1[add_id].reset(new Fqk_special_mul_gadget(pb, *fs[f_id], *g_RQ_at_P1s[add_id], *fs[f_id+1], FMT(annotation_prefix, " add_muls1_%zu", add_id))); + ++f_id; + add_muls2[add_id].reset(new Fqk_special_mul_gadget(pb, *fs[f_id], *g_RQ_at_P2s[add_id], *fs[f_id+1], FMT(annotation_prefix, " add_muls2_%zu", add_id))); + ++f_id; + add_muls3[add_id].reset(new Fqk_special_mul_gadget(pb, (f_id + 1 == f_count ? result : *fs[f_id+1]), *g_RQ_at_P3s[add_id], *fs[f_id], FMT(annotation_prefix, " add_muls3_%zu", add_id))); + ++f_id; + ++add_id; + } + } +} + +template +void mnt_e_times_e_over_e_miller_loop_gadget::generate_r1cs_constraints() +{ + fs[0]->generate_r1cs_equals_const_constraints(FqkT::one()); + + for (size_t i = 0; i < dbl_count; ++i) + { + doubling_steps1[i]->generate_r1cs_constraints(); + doubling_steps2[i]->generate_r1cs_constraints(); + doubling_steps3[i]->generate_r1cs_constraints(); + dbl_sqrs[i]->generate_r1cs_constraints(); + dbl_muls1[i]->generate_r1cs_constraints(); + dbl_muls2[i]->generate_r1cs_constraints(); + dbl_muls3[i]->generate_r1cs_constraints(); + } + + for (size_t i = 0; i < add_count; ++i) + { + addition_steps1[i]->generate_r1cs_constraints(); + addition_steps2[i]->generate_r1cs_constraints(); + addition_steps3[i]->generate_r1cs_constraints(); + add_muls1[i]->generate_r1cs_constraints(); + add_muls2[i]->generate_r1cs_constraints(); + add_muls3[i]->generate_r1cs_constraints(); + } +} + +template +void mnt_e_times_e_over_e_miller_loop_gadget::generate_r1cs_witness() +{ + fs[0]->generate_r1cs_witness(FqkT::one()); + + size_t add_id = 0; + size_t dbl_id = 0; + size_t f_id = 0; + + const auto &loop_count = pairing_selector::pairing_loop_count; + + bool found_nonzero = false; + std::vector NAF = find_wnaf(1, loop_count); + for (long i = NAF.size()-1; i >= 0; --i) + { + if (!found_nonzero) + { + /* this skips the MSB itself */ + found_nonzero |= (NAF[i] != 0); + continue; + } + + doubling_steps1[dbl_id]->generate_r1cs_witness(); + doubling_steps2[dbl_id]->generate_r1cs_witness(); + doubling_steps3[dbl_id]->generate_r1cs_witness(); + dbl_sqrs[dbl_id]->generate_r1cs_witness(); + ++f_id; + dbl_muls1[dbl_id]->generate_r1cs_witness(); + ++f_id; + dbl_muls2[dbl_id]->generate_r1cs_witness(); + ++f_id; + (f_id+1 == f_count ? result : *fs[f_id+1]).generate_r1cs_witness(fs[f_id]->get_element() * g_RR_at_P3s[dbl_id]->get_element().inverse()); + dbl_muls3[dbl_id]->generate_r1cs_witness(); + ++f_id; + ++dbl_id; + + if (NAF[i] != 0) + { + addition_steps1[add_id]->generate_r1cs_witness(); + addition_steps2[add_id]->generate_r1cs_witness(); + addition_steps3[add_id]->generate_r1cs_witness(); + add_muls1[add_id]->generate_r1cs_witness(); + ++f_id; + add_muls2[add_id]->generate_r1cs_witness(); + ++f_id; + (f_id+1 == f_count ? result : *fs[f_id+1]).generate_r1cs_witness(fs[f_id]->get_element() * g_RQ_at_P3s[add_id]->get_element().inverse()); + add_muls3[add_id]->generate_r1cs_witness(); + ++f_id; + ++add_id; + } + } +} + +template +void test_mnt_e_times_e_over_e_miller_loop(const std::string &annotation) +{ + protoboard > pb; + G1 > P1_val = Fr >::random_element() * G1 >::one(); + G2 > Q1_val = Fr >::random_element() * G2 >::one(); + + G1 > P2_val = Fr >::random_element() * G1 >::one(); + G2 > Q2_val = Fr >::random_element() * G2 >::one(); + + G1 > P3_val = Fr >::random_element() * G1 >::one(); + G2 > Q3_val = Fr >::random_element() * G2 >::one(); + + G1_variable P1(pb, "P1"); + G2_variable Q1(pb, "Q1"); + G1_variable P2(pb, "P2"); + G2_variable Q2(pb, "Q2"); + G1_variable P3(pb, "P3"); + G2_variable Q3(pb, "Q3"); + + G1_precomputation prec_P1; + precompute_G1_gadget compute_prec_P1(pb, P1, prec_P1, "compute_prec_P1"); + G1_precomputation prec_P2; + precompute_G1_gadget compute_prec_P2(pb, P2, prec_P2, "compute_prec_P2"); + G1_precomputation prec_P3; + precompute_G1_gadget compute_prec_P3(pb, P3, prec_P3, "compute_prec_P3"); + G2_precomputation prec_Q1; + precompute_G2_gadget compute_prec_Q1(pb, Q1, prec_Q1, "compute_prec_Q1"); + G2_precomputation prec_Q2; + precompute_G2_gadget compute_prec_Q2(pb, Q2, prec_Q2, "compute_prec_Q2"); + G2_precomputation prec_Q3; + precompute_G2_gadget compute_prec_Q3(pb, Q3, prec_Q3, "compute_prec_Q3"); + + Fqk_variable result(pb, "result"); + mnt_e_times_e_over_e_miller_loop_gadget miller(pb, prec_P1, prec_Q1, prec_P2, prec_Q2, prec_P3, prec_Q3, result, "miller"); + + PROFILE_CONSTRAINTS(pb, "precompute P") + { + compute_prec_P1.generate_r1cs_constraints(); + compute_prec_P2.generate_r1cs_constraints(); + compute_prec_P3.generate_r1cs_constraints(); + } + PROFILE_CONSTRAINTS(pb, "precompute Q") + { + compute_prec_Q1.generate_r1cs_constraints(); + compute_prec_Q2.generate_r1cs_constraints(); + compute_prec_Q3.generate_r1cs_constraints(); + } + PROFILE_CONSTRAINTS(pb, "Miller loop") + { + miller.generate_r1cs_constraints(); + } + PRINT_CONSTRAINT_PROFILING(); + + P1.generate_r1cs_witness(P1_val); + compute_prec_P1.generate_r1cs_witness(); + Q1.generate_r1cs_witness(Q1_val); + compute_prec_Q1.generate_r1cs_witness(); + P2.generate_r1cs_witness(P2_val); + compute_prec_P2.generate_r1cs_witness(); + Q2.generate_r1cs_witness(Q2_val); + compute_prec_Q2.generate_r1cs_witness(); + P3.generate_r1cs_witness(P3_val); + compute_prec_P3.generate_r1cs_witness(); + Q3.generate_r1cs_witness(Q3_val); + compute_prec_Q3.generate_r1cs_witness(); + miller.generate_r1cs_witness(); + assert(pb.is_satisfied()); + + affine_ate_G1_precomp > native_prec_P1 = other_curve::affine_ate_precompute_G1(P1_val); + affine_ate_G2_precomp > native_prec_Q1 = other_curve::affine_ate_precompute_G2(Q1_val); + affine_ate_G1_precomp > native_prec_P2 = other_curve::affine_ate_precompute_G1(P2_val); + affine_ate_G2_precomp > native_prec_Q2 = other_curve::affine_ate_precompute_G2(Q2_val); + affine_ate_G1_precomp > native_prec_P3 = other_curve::affine_ate_precompute_G1(P3_val); + affine_ate_G2_precomp > native_prec_Q3 = other_curve::affine_ate_precompute_G2(Q3_val); + Fqk > native_result = (other_curve::affine_ate_miller_loop(native_prec_P1, native_prec_Q1) * + other_curve::affine_ate_miller_loop(native_prec_P2, native_prec_Q2) * + other_curve::affine_ate_miller_loop(native_prec_P3, native_prec_Q3).inverse()); + + assert(result.get_element() == native_result); + printf("number of constraints for e times e over e Miller loop (Fr is %s) = %zu\n", annotation.c_str(), pb.num_constraints()); +} + +} // libsnark + +#endif // WEIERSTRASS_MILLER_LOOP_TCC_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/pairing/weierstrass_precomputation.hpp b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/pairing/weierstrass_precomputation.hpp new file mode 100644 index 0000000..14c9dbb --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/pairing/weierstrass_precomputation.hpp @@ -0,0 +1,280 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for pairing precomputation gadgets. + + The gadgets verify correct precomputation of values for the G1 and G2 variables. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef WEIERSTRASS_PRECOMPUTATION_HPP_ +#define WEIERSTRASS_PRECOMPUTATION_HPP_ + +#include +#include "gadgetlib1/gadgets/curves/weierstrass_g1_gadget.hpp" +#include "gadgetlib1/gadgets/curves/weierstrass_g2_gadget.hpp" +#include "gadgetlib1/gadgets/pairing/pairing_params.hpp" + +namespace libsnark { + +/**************************** G1 Precomputation ******************************/ + +/** + * Not a gadget. It only holds values. + */ +template +class G1_precomputation { +public: + typedef Fr FieldT; + typedef Fqe > FqeT; + typedef Fqk > FqkT; + + std::shared_ptr > P; + std::shared_ptr > PY_twist_squared; + + G1_precomputation(); + G1_precomputation(protoboard &pb, + const G1 > &P, + const std::string &annotation_prefix); +}; + +/** + * Gadget that verifies correct precomputation of the G1 variable. + */ +template +class precompute_G1_gadget : public gadget > { +public: + typedef Fqe > FqeT; + typedef Fqk > FqkT; + + G1_precomputation &precomp; // must be a reference. + + /* two possible pre-computations one for mnt4 and one for mnt6 */ + template + precompute_G1_gadget(protoboard &pb, + const G1_variable &P, + G1_precomputation &precomp, // will allocate this inside + const std::string &annotation_prefix, + const typename std::enable_if >::extension_degree() == 4, FieldT>::type& = FieldT()) : + gadget(pb, annotation_prefix), + precomp(precomp) + { + pb_linear_combination c0, c1; + c0.assign(pb, P.Y * ((mnt4_twist).squared().c0)); + c1.assign(pb, P.Y * ((mnt4_twist).squared().c1)); + + precomp.P.reset(new G1_variable(P)); + precomp.PY_twist_squared.reset(new Fqe_variable(pb, c0, c1, FMT(annotation_prefix, " PY_twist_squared"))); + } + + template + precompute_G1_gadget(protoboard &pb, + const G1_variable &P, + G1_precomputation &precomp, // will allocate this inside + const std::string &annotation_prefix, + const typename std::enable_if >::extension_degree() == 6, FieldT>::type& = FieldT()) : + gadget(pb, annotation_prefix), + precomp(precomp) + { + pb_linear_combination c0, c1, c2; + c0.assign(pb, P.Y * ((mnt6_twist).squared().c0)); + c1.assign(pb, P.Y * ((mnt6_twist).squared().c1)); + c2.assign(pb, P.Y * ((mnt6_twist).squared().c2)); + + precomp.P.reset(new G1_variable(P)); + precomp.PY_twist_squared.reset(new Fqe_variable(pb, c0, c1, c2, FMT(annotation_prefix, " PY_twist_squared"))); + } + + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +template +void test_G1_variable_precomp(const std::string &annotation); + + +/**************************** G2 Precomputation ******************************/ + +/** + * Not a gadget. It only holds values. + */ +template +class precompute_G2_gadget_coeffs { +public: + typedef Fr FieldT; + typedef Fqe > FqeT; + typedef Fqk > FqkT; + + std::shared_ptr > RX; + std::shared_ptr > RY; + std::shared_ptr > gamma; + std::shared_ptr > gamma_X; + + precompute_G2_gadget_coeffs(); + precompute_G2_gadget_coeffs(protoboard &pb, + const std::string &annotation_prefix); + precompute_G2_gadget_coeffs(protoboard &pb, + const G2_variable &Q, + const std::string &annotation_prefix); +}; + +/** + * Not a gadget. It only holds values. + */ +template +class G2_precomputation { +public: + typedef Fr FieldT; + typedef Fqe > FqeT; + typedef Fqk > FqkT; + + std::shared_ptr > Q; + + std::vector > > coeffs; + + G2_precomputation(); + G2_precomputation(protoboard &pb, + const G2 > &Q_val, + const std::string &annotation_prefix); +}; + +/** + * Technical note: + * + * QX and QY -- X and Y coordinates of Q + * + * initialization: + * coeffs[0].RX = QX + * coeffs[0].RY = QY + * + * G2_precompute_doubling_step relates coeffs[i] and coeffs[i+1] as follows + * + * coeffs[i] + * gamma = (3 * RX^2 + twist_coeff_a) * (2*RY).inverse() + * gamma_X = gamma * RX + * + * coeffs[i+1] + * RX = prev_gamma^2 - (2*prev_RX) + * RY = prev_gamma * (prev_RX - RX) - prev_RY + */ +template +class precompute_G2_gadget_doubling_step : public gadget > { +public: + typedef Fr FieldT; + typedef Fqe > FqeT; + typedef Fqk > FqkT; + + precompute_G2_gadget_coeffs cur; + precompute_G2_gadget_coeffs next; + + std::shared_ptr > RXsquared; + std::shared_ptr > compute_RXsquared; + std::shared_ptr > three_RXsquared_plus_a; + std::shared_ptr > two_RY; + std::shared_ptr > compute_gamma; + std::shared_ptr > compute_gamma_X; + + std::shared_ptr > next_RX_plus_two_RX; + std::shared_ptr > compute_next_RX; + + std::shared_ptr > RX_minus_next_RX; + std::shared_ptr > RY_plus_next_RY; + std::shared_ptr > compute_next_RY; + + precompute_G2_gadget_doubling_step(protoboard &pb, + const precompute_G2_gadget_coeffs &cur, + const precompute_G2_gadget_coeffs &next, + const std::string &annotation_prefix); + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +/** + * Technical note: + * + * G2_precompute_addition_step relates coeffs[i] and coeffs[i+1] as follows + * + * coeffs[i] + * gamma = (RY - QY) * (RX - QX).inverse() + * gamma_X = gamma * QX + * + * coeffs[i+1] + * RX = prev_gamma^2 + (prev_RX + QX) + * RY = prev_gamma * (prev_RX - RX) - prev_RY + * + * (where prev_ in [i+1] refer to things from [i]) + * + * If invert_Q is set to true: use -QY in place of QY everywhere above. + */ +template +class precompute_G2_gadget_addition_step : public gadget > { +public: + typedef Fr FieldT; + typedef Fqe > FqeT; + typedef Fqk > FqkT; + + bool invert_Q; + precompute_G2_gadget_coeffs cur; + precompute_G2_gadget_coeffs next; + G2_variable Q; + + std::shared_ptr > RY_minus_QY; + std::shared_ptr > RX_minus_QX; + std::shared_ptr > compute_gamma; + std::shared_ptr > compute_gamma_X; + + std::shared_ptr > next_RX_plus_RX_plus_QX; + std::shared_ptr > compute_next_RX; + + std::shared_ptr > RX_minus_next_RX; + std::shared_ptr > RY_plus_next_RY; + std::shared_ptr > compute_next_RY; + + precompute_G2_gadget_addition_step(protoboard &pb, + const bool invert_Q, + const precompute_G2_gadget_coeffs &cur, + const precompute_G2_gadget_coeffs &next, + const G2_variable &Q, + const std::string &annotation_prefix); + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +/** + * Gadget that verifies correct precomputation of the G2 variable. + */ +template +class precompute_G2_gadget : public gadget > { +public: + typedef Fr FieldT; + typedef Fqe > FqeT; + typedef Fqk > FqkT; + + std::vector > > addition_steps; + std::vector > > doubling_steps; + + size_t add_count; + size_t dbl_count; + + G2_precomputation &precomp; // important to have a reference here + + precompute_G2_gadget(protoboard &pb, + const G2_variable &Q, + G2_precomputation &precomp, // will allocate this inside + const std::string &annotation_prefix); + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +template +void test_G2_variable_precomp(const std::string &annotation); + +} // libsnark + +#include "gadgetlib1/gadgets/pairing/weierstrass_precomputation.tcc" + +#endif // WEIERSTRASS_PRECOMPUTATION_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/pairing/weierstrass_precomputation.tcc b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/pairing/weierstrass_precomputation.tcc new file mode 100644 index 0000000..9cd1126 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/pairing/weierstrass_precomputation.tcc @@ -0,0 +1,444 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for pairing precomputation gadgets. + + See weierstrass_precomputation.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef WEIERSTRASS_PRECOMPUTATION_TCC_ +#define WEIERSTRASS_PRECOMPUTATION_TCC_ + +#include +#include "gadgetlib1/gadgets/pairing/mnt_pairing_params.hpp" + +namespace libsnark { + +template +G1_precomputation::G1_precomputation() +{ + // will be filled in precompute_G1_gadget, so do nothing here +} + +template +G1_precomputation::G1_precomputation(protoboard &pb, + const G1 > &P_val, + const std::string &annotation_prefix) +{ + G1 > P_val_copy = P_val; + P_val_copy.to_affine_coordinates(); + P.reset(new G1_variable(pb, P_val_copy, FMT(annotation_prefix, " P"))); + PY_twist_squared.reset(new Fqe_variable(pb, P_val_copy.Y() * G2 >::twist.squared(), " PY_twist_squared")); +} + +template +void precompute_G1_gadget::generate_r1cs_constraints() +{ + /* the same for neither ppT = mnt4 nor ppT = mnt6 */ +} + +template +void precompute_G1_gadget::generate_r1cs_witness() +{ + precomp.PY_twist_squared->evaluate(); /* the same for both ppT = mnt4 and ppT = mnt6 */ +} + +template +void test_G1_variable_precomp(const std::string &annotation) +{ + protoboard > pb; + G1 > g_val = Fr >::random_element() * G1 >::one(); + + G1_variable g(pb, "g"); + G1_precomputation precomp; + precompute_G1_gadget do_precomp(pb, g, precomp, "do_precomp"); + do_precomp.generate_r1cs_constraints(); + + g.generate_r1cs_witness(g_val); + do_precomp.generate_r1cs_witness(); + assert(pb.is_satisfied()); + + G1_precomputation const_precomp(pb, g_val, "const_precomp"); + + affine_ate_G1_precomp > native_precomp = other_curve::affine_ate_precompute_G1(g_val); + assert(precomp.PY_twist_squared->get_element() == native_precomp.PY_twist_squared); + assert(const_precomp.PY_twist_squared->get_element() == native_precomp.PY_twist_squared); + + printf("number of constraints for G1 precomp (Fr is %s) = %zu\n", annotation.c_str(), pb.num_constraints()); +} + +template +G2_precomputation::G2_precomputation() +{ +} + +template +G2_precomputation::G2_precomputation(protoboard &pb, + const G2 > &Q_val, + const std::string &annotation_prefix) +{ + Q.reset(new G2_variable(pb, Q_val, FMT(annotation_prefix, " Q"))); + const affine_ate_G2_precomp > native_precomp = other_curve::affine_ate_precompute_G2(Q_val); + + coeffs.resize(native_precomp.coeffs.size() + 1); // the last precomp remains for convenient programming + for (size_t i = 0; i < native_precomp.coeffs.size(); ++i) + { + coeffs[i].reset(new precompute_G2_gadget_coeffs()); + coeffs[i]->RX.reset(new Fqe_variable(pb, native_precomp.coeffs[i].old_RX, FMT(annotation_prefix, " RX"))); + coeffs[i]->RY.reset(new Fqe_variable(pb, native_precomp.coeffs[i].old_RY, FMT(annotation_prefix, " RY"))); + coeffs[i]->gamma.reset(new Fqe_variable(pb, native_precomp.coeffs[i].gamma, FMT(annotation_prefix, " gamma"))); + coeffs[i]->gamma_X.reset(new Fqe_variable(pb, native_precomp.coeffs[i].gamma_X, FMT(annotation_prefix, " gamma_X"))); + } +} + +template +precompute_G2_gadget_coeffs::precompute_G2_gadget_coeffs() +{ + // we will be filled in precomputed case of precompute_G2_gadget, so do nothing here +} + +template +precompute_G2_gadget_coeffs::precompute_G2_gadget_coeffs(protoboard &pb, + const std::string &annotation_prefix) +{ + RX.reset(new Fqe_variable(pb, FMT(annotation_prefix, " RX"))); + RY.reset(new Fqe_variable(pb, FMT(annotation_prefix, " RY"))); + gamma.reset(new Fqe_variable(pb, FMT(annotation_prefix, " gamma"))); + gamma_X.reset(new Fqe_variable(pb, FMT(annotation_prefix, " gamma_X"))); +} + +template +precompute_G2_gadget_coeffs::precompute_G2_gadget_coeffs(protoboard &pb, + const G2_variable &Q, + const std::string &annotation_prefix) +{ + RX.reset(new Fqe_variable(*(Q.X))); + RY.reset(new Fqe_variable(*(Q.Y))); + gamma.reset(new Fqe_variable(pb, FMT(annotation_prefix, " gamma"))); + gamma_X.reset(new Fqe_variable(pb, FMT(annotation_prefix, " gamma_X"))); +} + +/* + QX and QY -- X and Y coordinates of Q + + initialization: + coeffs[0].RX = QX + coeffs[0].RY = QY + + G2_precompute_doubling_step relates coeffs[i] and coeffs[i+1] as follows + + coeffs[i] + gamma = (3 * RX^2 + twist_coeff_a) * (2*RY).inverse() + gamma_X = gamma * RX + + coeffs[i+1] + RX = prev_gamma^2 - (2*prev_RX) + RY = prev_gamma * (prev_RX - RX) - prev_RY + */ + +template +precompute_G2_gadget_doubling_step::precompute_G2_gadget_doubling_step(protoboard &pb, + const precompute_G2_gadget_coeffs &cur, + const precompute_G2_gadget_coeffs &next, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), + cur(cur), + next(next) +{ + RXsquared.reset(new Fqe_variable(pb, FMT(annotation_prefix, " RXsquared"))); + compute_RXsquared.reset(new Fqe_sqr_gadget(pb, *(cur.RX), *RXsquared, FMT(annotation_prefix, " compute_RXsquared"))); + three_RXsquared_plus_a.reset(new Fqe_variable((*RXsquared) * FieldT(3) + G2 >::coeff_a)); + two_RY.reset(new Fqe_variable(*(cur.RY) * FieldT(2))); + + compute_gamma.reset(new Fqe_mul_gadget(pb, *(cur.gamma), *two_RY, *three_RXsquared_plus_a, FMT(annotation_prefix, " compute_gamma"))); + compute_gamma_X.reset(new Fqe_mul_gadget(pb, *(cur.gamma), *(cur.RX), *(cur.gamma_X), FMT(annotation_prefix, " compute_gamma_X"))); + + next_RX_plus_two_RX.reset(new Fqe_variable(*(next.RX) + *(cur.RX) * FieldT(2))); + compute_next_RX.reset(new Fqe_sqr_gadget(pb, *(cur.gamma), *next_RX_plus_two_RX, FMT(annotation_prefix, " compute_next_RX"))); + + RX_minus_next_RX.reset(new Fqe_variable(*(cur.RX) + *(next.RX) * (-FieldT::one()))); + RY_plus_next_RY.reset(new Fqe_variable(*(cur.RY) + *(next.RY))); + compute_next_RY.reset(new Fqe_mul_gadget(pb, *(cur.gamma), *RX_minus_next_RX, *RY_plus_next_RY, FMT(annotation_prefix, " compute_next_RY"))); +} + +template +void precompute_G2_gadget_doubling_step::generate_r1cs_constraints() +{ + compute_RXsquared->generate_r1cs_constraints(); + compute_gamma->generate_r1cs_constraints(); + compute_gamma_X->generate_r1cs_constraints(); + compute_next_RX->generate_r1cs_constraints(); + compute_next_RY->generate_r1cs_constraints(); +} + +template +void precompute_G2_gadget_doubling_step::generate_r1cs_witness() +{ + compute_RXsquared->generate_r1cs_witness(); + two_RY->evaluate(); + three_RXsquared_plus_a->evaluate(); + + const FqeT three_RXsquared_plus_a_val = three_RXsquared_plus_a->get_element(); + const FqeT two_RY_val = two_RY->get_element(); + const FqeT gamma_val = three_RXsquared_plus_a_val * two_RY_val.inverse(); + cur.gamma->generate_r1cs_witness(gamma_val); + + compute_gamma->generate_r1cs_witness(); + compute_gamma_X->generate_r1cs_witness(); + + const FqeT RX_val = cur.RX->get_element(); + const FqeT RY_val = cur.RY->get_element(); + const FqeT next_RX_val = gamma_val.squared() - RX_val - RX_val; + const FqeT next_RY_val = gamma_val * (RX_val - next_RX_val) - RY_val; + + next.RX->generate_r1cs_witness(next_RX_val); + next.RY->generate_r1cs_witness(next_RY_val); + + RX_minus_next_RX->evaluate(); + RY_plus_next_RY->evaluate(); + + compute_next_RX->generate_r1cs_witness(); + compute_next_RY->generate_r1cs_witness(); +} + +/* + G2_precompute_addition_step relates coeffs[i] and coeffs[i+1] as follows + + coeffs[i] + gamma = (RY - QY) * (RX - QX).inverse() + gamma_X = gamma * QX + + coeffs[i+1] + RX = prev_gamma^2 - (prev_RX + QX) + RY = prev_gamma * (prev_RX - RX) - prev_RY + + (where prev_ in [i+1] refer to things from [i]) + + If invert_Q is set to true: use -QY in place of QY everywhere above. + */ +template +precompute_G2_gadget_addition_step::precompute_G2_gadget_addition_step(protoboard &pb, + const bool invert_Q, + const precompute_G2_gadget_coeffs &cur, + const precompute_G2_gadget_coeffs &next, + const G2_variable &Q, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), + invert_Q(invert_Q), + cur(cur), + next(next), + Q(Q) +{ + RY_minus_QY.reset(new Fqe_variable(*(cur.RY) + *(Q.Y) * (!invert_Q ? -FieldT::one() : FieldT::one()))); + + RX_minus_QX.reset(new Fqe_variable(*(cur.RX) + *(Q.X) * (-FieldT::one()))); + compute_gamma.reset(new Fqe_mul_gadget(pb, *(cur.gamma), *RX_minus_QX, *RY_minus_QY, FMT(annotation_prefix, " compute_gamma"))); + compute_gamma_X.reset(new Fqe_mul_gadget(pb, *(cur.gamma), *(Q.X), *(cur.gamma_X), FMT(annotation_prefix, " compute_gamma_X"))); + + next_RX_plus_RX_plus_QX.reset(new Fqe_variable(*(next.RX) + *(cur.RX) + *(Q.X))); + compute_next_RX.reset(new Fqe_sqr_gadget(pb, *(cur.gamma), *next_RX_plus_RX_plus_QX, FMT(annotation_prefix, " compute_next_RX"))); + + RX_minus_next_RX.reset(new Fqe_variable(*(cur.RX) + *(next.RX) * (-FieldT::one()))); + RY_plus_next_RY.reset(new Fqe_variable(*(cur.RY) + *(next.RY))); + compute_next_RY.reset(new Fqe_mul_gadget(pb, *(cur.gamma), *RX_minus_next_RX, *RY_plus_next_RY, FMT(annotation_prefix, " compute_next_RY"))); +} + +template +void precompute_G2_gadget_addition_step::generate_r1cs_constraints() +{ + compute_gamma->generate_r1cs_constraints(); + compute_gamma_X->generate_r1cs_constraints(); + compute_next_RX->generate_r1cs_constraints(); + compute_next_RY->generate_r1cs_constraints(); +} + +template +void precompute_G2_gadget_addition_step::generate_r1cs_witness() +{ + RY_minus_QY->evaluate(); + RX_minus_QX->evaluate(); + + const FqeT RY_minus_QY_val = RY_minus_QY->get_element(); + const FqeT RX_minus_QX_val = RX_minus_QX->get_element(); + const FqeT gamma_val = RY_minus_QY_val * RX_minus_QX_val.inverse(); + cur.gamma->generate_r1cs_witness(gamma_val); + + compute_gamma->generate_r1cs_witness(); + compute_gamma_X->generate_r1cs_witness(); + + const FqeT RX_val = cur.RX->get_element(); + const FqeT RY_val = cur.RY->get_element(); + const FqeT QX_val = Q.X->get_element(); + const FqeT next_RX_val = gamma_val.squared() - RX_val - QX_val; + const FqeT next_RY_val = gamma_val * (RX_val - next_RX_val) - RY_val; + + next.RX->generate_r1cs_witness(next_RX_val); + next.RY->generate_r1cs_witness(next_RY_val); + + next_RX_plus_RX_plus_QX->evaluate(); + RX_minus_next_RX->evaluate(); + RY_plus_next_RY->evaluate(); + + compute_next_RX->generate_r1cs_witness(); + compute_next_RY->generate_r1cs_witness(); +} + +template +precompute_G2_gadget::precompute_G2_gadget(protoboard &pb, + const G2_variable &Q, + G2_precomputation &precomp, // will allocate this inside + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), + precomp(precomp) +{ + precomp.Q.reset(new G2_variable(Q)); + + const auto &loop_count = pairing_selector::pairing_loop_count; + size_t coeff_count = 1; // the last RX/RY are unused in Miller loop, but will need to get allocated somehow + this->add_count = 0; + this->dbl_count = 0; + + bool found_nonzero = false; + std::vector NAF = find_wnaf(1, loop_count); + for (long i = NAF.size()-1; i >= 0; --i) + { + if (!found_nonzero) + { + /* this skips the MSB itself */ + found_nonzero |= (NAF[i] != 0); + continue; + } + + ++dbl_count; + ++coeff_count; + + if (NAF[i] != 0) + { + ++add_count; + ++coeff_count; + } + } + + precomp.coeffs.resize(coeff_count); + addition_steps.resize(add_count); + doubling_steps.resize(dbl_count); + + precomp.coeffs[0].reset(new precompute_G2_gadget_coeffs(pb, Q, FMT(annotation_prefix, " coeffs_0"))); + for (size_t i = 1; i < coeff_count; ++i) + { + precomp.coeffs[i].reset(new precompute_G2_gadget_coeffs(pb, FMT(annotation_prefix, " coeffs_%zu", i))); + } + + size_t add_id = 0; + size_t dbl_id = 0; + size_t coeff_id = 0; + + found_nonzero = false; + for (long i = NAF.size()-1; i >= 0; --i) + { + if (!found_nonzero) + { + /* this skips the MSB itself */ + found_nonzero |= (NAF[i] != 0); + continue; + } + + doubling_steps[dbl_id].reset(new precompute_G2_gadget_doubling_step(pb, *(precomp.coeffs[coeff_id]), *(precomp.coeffs[coeff_id+1]), + FMT(annotation_prefix, " doubling_steps_%zu", dbl_id))); + ++dbl_id; + ++coeff_id; + + if (NAF[i] != 0) + { + addition_steps[add_id].reset(new precompute_G2_gadget_addition_step(pb, NAF[i] < 0, *(precomp.coeffs[coeff_id]), *(precomp.coeffs[coeff_id+1]), Q, + FMT(annotation_prefix, " addition_steps_%zu", add_id))); + ++add_id; + ++coeff_id; + } + } +} + +template +void precompute_G2_gadget::generate_r1cs_constraints() +{ + for (size_t i = 0; i < dbl_count; ++i) + { + doubling_steps[i]->generate_r1cs_constraints(); + } + + for (size_t i = 0; i < add_count; ++i) + { + addition_steps[i]->generate_r1cs_constraints(); + } +} + +template +void precompute_G2_gadget::generate_r1cs_witness() +{ + precomp.coeffs[0]->RX->generate_r1cs_witness(precomp.Q->X->get_element()); + precomp.coeffs[0]->RY->generate_r1cs_witness(precomp.Q->Y->get_element()); + + const auto &loop_count = pairing_selector::pairing_loop_count; + + size_t add_id = 0; + size_t dbl_id = 0; + + bool found_nonzero = false; + std::vector NAF = find_wnaf(1, loop_count); + for (long i = NAF.size()-1; i >= 0; --i) + { + if (!found_nonzero) + { + /* this skips the MSB itself */ + found_nonzero |= (NAF[i] != 0); + continue; + } + + doubling_steps[dbl_id]->generate_r1cs_witness(); + ++dbl_id; + + if (NAF[i] != 0) + { + addition_steps[add_id]->generate_r1cs_witness(); + ++add_id; + } + } +} + +template +void test_G2_variable_precomp(const std::string &annotation) +{ + protoboard > pb; + G2 > g_val = Fr >::random_element() * G2 >::one(); + + G2_variable g(pb, "g"); + G2_precomputation precomp; + precompute_G2_gadget do_precomp(pb, g, precomp, "do_precomp"); + do_precomp.generate_r1cs_constraints(); + + g.generate_r1cs_witness(g_val); + do_precomp.generate_r1cs_witness(); + assert(pb.is_satisfied()); + + affine_ate_G2_precomp > native_precomp = other_curve::affine_ate_precompute_G2(g_val); + + assert(precomp.coeffs.size() - 1 == native_precomp.coeffs.size()); // the last precomp is unused, but remains for convenient programming + for (size_t i = 0; i < native_precomp.coeffs.size(); ++i) + { + assert(precomp.coeffs[i]->RX->get_element() == native_precomp.coeffs[i].old_RX); + assert(precomp.coeffs[i]->RY->get_element() == native_precomp.coeffs[i].old_RY); + assert(precomp.coeffs[i]->gamma->get_element() == native_precomp.coeffs[i].gamma); + assert(precomp.coeffs[i]->gamma_X->get_element() == native_precomp.coeffs[i].gamma_X); + } + + printf("number of constraints for G2 precomp (Fr is %s) = %zu\n", annotation.c_str(), pb.num_constraints()); +} + +} // libsnark + +#endif // WEIERSTRASS_PRECOMPUTATION_TCC_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/routing/as_waksman_routing_gadget.hpp b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/routing/as_waksman_routing_gadget.hpp new file mode 100644 index 0000000..8fc606d --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/routing/as_waksman_routing_gadget.hpp @@ -0,0 +1,82 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for the AS-Waksman routing gadget. + + The gadget verifies that the outputs are a permutation of the inputs, + by use of an AS-Waksman network. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef AS_WAKSMAN_ROUTING_GADGET_HPP_ +#define AS_WAKSMAN_ROUTING_GADGET_HPP_ + +#include "gadgetlib1/protoboard.hpp" +#include "gadgetlib1/gadgets/basic_gadgets.hpp" +#include "common/data_structures/integer_permutation.hpp" +#include "common/routing_algorithms/as_waksman_routing_algorithm.hpp" + +namespace libsnark { + +template +class as_waksman_routing_gadget : public gadget { +private: + /* + Indexing conventions: + + routed_packets[column_idx][packet_idx][subpacket_idx] + pack_inputs/unpack_outputs[packet_idx] + asw_switch_bits[column_idx][row_idx] + + Where column_idx ranges is in range 0 .. width and packet_idx is + in range 0 .. num_packets-1. + + Note that unlike in Bene\v{s} routing networks row_idx are + *not* necessarily consecutive; similarly for straight edges + routed_packets[column_idx][packet_idx] will *reuse* previously + allocated variables. + + */ + std::vector > > routed_packets; + std::vector > pack_inputs, unpack_outputs; + + /* + If #packets = 1 then we can route without explicit switch bits + (and save half the constraints); in this case asw_switch_bits will + be unused. + + For asw_switch_bits 0 corresponds to switch off (straight + connection), and 1 corresponds to switch on (crossed + connection). + */ + std::vector > > asw_switch_bits; + as_waksman_topology neighbors; +public: + const size_t num_packets; + const size_t num_columns; + const std::vector> routing_input_bits; + const std::vector> routing_output_bits; + + const size_t packet_size, num_subpackets; + + as_waksman_routing_gadget(protoboard &pb, + const size_t num_packets, + const std::vector> &routing_input_bits, + const std::vector> &routing_output_bits, + const std::string& annotation_prefix=""); + void generate_r1cs_constraints(); + void generate_r1cs_witness(const integer_permutation& permutation); +}; + +template +void test_as_waksman_routing_gadget(const size_t num_packets, const size_t packet_size); + +} // libsnark + +#include "gadgetlib1/gadgets/routing/as_waksman_routing_gadget.tcc" + +#endif // AS_WAKSMAN_ROUTING_GADGET_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/routing/as_waksman_routing_gadget.tcc b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/routing/as_waksman_routing_gadget.tcc new file mode 100644 index 0000000..74f386a --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/routing/as_waksman_routing_gadget.tcc @@ -0,0 +1,294 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for the AS-Waksman routing gadget. + + See as_waksman_routing_gadget.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef AS_WAKSMAN_ROUTING_GADGET_TCC_ +#define AS_WAKSMAN_ROUTING_GADGET_TCC_ + +#include + +#include "common/routing_algorithms/as_waksman_routing_algorithm.hpp" +#include "common/profiling.hpp" + +namespace libsnark { + +template +as_waksman_routing_gadget::as_waksman_routing_gadget(protoboard &pb, + const size_t num_packets, + const std::vector > &routing_input_bits, + const std::vector > &routing_output_bits, + const std::string& annotation_prefix) : + gadget(pb, annotation_prefix), + num_packets(num_packets), + num_columns(as_waksman_num_columns(num_packets)), + routing_input_bits(routing_input_bits), + routing_output_bits(routing_output_bits), + packet_size(routing_input_bits[0].size()), + num_subpackets(div_ceil(packet_size, FieldT::capacity())) +{ + neighbors = generate_as_waksman_topology(num_packets); + routed_packets.resize(num_columns+1); + + /* Two pass allocation. First allocate LHS packets, then for every + switch either copy over the variables from previously allocated + to allocate target packets */ + routed_packets[0].resize(num_packets); + for (size_t packet_idx = 0; packet_idx < num_packets; ++packet_idx) + { + routed_packets[0][packet_idx].allocate(pb, num_subpackets, FMT(annotation_prefix, " routed_packets_0_%zu", packet_idx)); + } + + for (size_t column_idx = 0; column_idx < num_columns; ++column_idx) + { + routed_packets[column_idx+1].resize(num_packets); + + for (size_t row_idx = 0; row_idx < num_packets; ++row_idx) + { + if (neighbors[column_idx][row_idx].first == neighbors[column_idx][row_idx].second) + { + /* This is a straight edge, so just copy over the previously allocated subpackets */ + routed_packets[column_idx+1][neighbors[column_idx][row_idx].first] = routed_packets[column_idx][row_idx]; + } + else + { + const size_t straight_edge = neighbors[column_idx][row_idx].first; + const size_t cross_edge = neighbors[column_idx][row_idx].second; + routed_packets[column_idx+1][straight_edge].allocate(pb, num_subpackets, FMT(annotation_prefix, " routed_packets_%zu_%zu", column_idx+1, straight_edge)); + routed_packets[column_idx+1][cross_edge].allocate(pb, num_subpackets, FMT(annotation_prefix, " routed_packets_%zu_%zu", column_idx+1, cross_edge)); + ++row_idx; /* skip the next idx, as it to refers to the same packets */ + } + } + } + + /* create packing/unpacking gadgets */ + pack_inputs.reserve(num_packets); unpack_outputs.reserve(num_packets); + for (size_t packet_idx = 0; packet_idx < num_packets; ++packet_idx) + { + pack_inputs.emplace_back( + multipacking_gadget(pb, + pb_variable_array(routing_input_bits[packet_idx].begin(), routing_input_bits[packet_idx].end()), + routed_packets[0][packet_idx], + FieldT::capacity(), + FMT(this->annotation_prefix, " pack_inputs_%zu", packet_idx))); + unpack_outputs.emplace_back( + multipacking_gadget(pb, + pb_variable_array(routing_output_bits[packet_idx].begin(), routing_output_bits[packet_idx].end()), + routed_packets[num_columns][packet_idx], + FieldT::capacity(), + FMT(this->annotation_prefix, " unpack_outputs_%zu", packet_idx))); + } + + /* allocate switch bits */ + if (num_subpackets > 1) + { + asw_switch_bits.resize(num_columns); + + for (size_t column_idx = 0; column_idx < num_columns; ++column_idx) + { + for (size_t row_idx = 0; row_idx < num_packets; ++row_idx) + { + if (neighbors[column_idx][row_idx].first != neighbors[column_idx][row_idx].second) + { + asw_switch_bits[column_idx][row_idx].allocate(pb, FMT(annotation_prefix, " asw_switch_bits_%zu_%zu", column_idx, row_idx)); + ++row_idx; /* next row_idx corresponds to the same switch, so skip it */ + } + } + } + } +} + +template +void as_waksman_routing_gadget::generate_r1cs_constraints() +{ + /* packing/unpacking */ + for (size_t packet_idx = 0; packet_idx < num_packets; ++packet_idx) + { + pack_inputs[packet_idx].generate_r1cs_constraints(false); + unpack_outputs[packet_idx].generate_r1cs_constraints(true); + } + + /* actual routing constraints */ + for (size_t column_idx = 0; column_idx < num_columns; ++column_idx) + { + for (size_t row_idx = 0; row_idx < num_packets; ++row_idx) + { + if (neighbors[column_idx][row_idx].first == neighbors[column_idx][row_idx].second) + { + /* if there is no switch at this position, then just continue with next row_idx */ + continue; + } + + if (num_subpackets == 1) + { + /* easy case: require that + (cur-straight_edge)*(cur-cross_edge) = 0 for both + switch inputs */ + for (size_t switch_input : { row_idx, row_idx+1 }) + { + const size_t straight_edge = neighbors[column_idx][switch_input].first; + const size_t cross_edge = neighbors[column_idx][switch_input].second; + + this->pb.add_r1cs_constraint( + r1cs_constraint(routed_packets[column_idx][switch_input][0] - routed_packets[column_idx+1][straight_edge][0], + routed_packets[column_idx][switch_input][0] - routed_packets[column_idx+1][cross_edge][0], + 0), + FMT(this->annotation_prefix, " easy_route_%zu_%zu", column_idx, switch_input)); + } + } + else + { + /* require switching bit to be boolean */ + generate_boolean_r1cs_constraint(this->pb, asw_switch_bits[column_idx][row_idx], + FMT(this->annotation_prefix, " asw_switch_bits_%zu_%zu", column_idx, row_idx)); + + /* route forward according to the switch bit */ + for (size_t subpacket_idx = 0; subpacket_idx < num_subpackets; ++subpacket_idx) + { + /* + (1-switch_bit) * (cur-straight_edge) + switch_bit * (cur-cross_edge) = 0 + switch_bit * (cross_edge-straight_edge) = cur-straight_edge + */ + for (size_t switch_input : { row_idx, row_idx+1 }) + { + const size_t straight_edge = neighbors[column_idx][switch_input].first; + const size_t cross_edge = neighbors[column_idx][switch_input].second; + + this->pb.add_r1cs_constraint( + r1cs_constraint( + asw_switch_bits[column_idx][row_idx], + routed_packets[column_idx+1][cross_edge][subpacket_idx] - routed_packets[column_idx+1][straight_edge][subpacket_idx], + routed_packets[column_idx][switch_input][subpacket_idx] - routed_packets[column_idx+1][straight_edge][subpacket_idx]), + FMT(this->annotation_prefix, " route_forward_%zu_%zu_%zu", column_idx, switch_input, subpacket_idx)); + } + } + } + + /* we processed both switch inputs at once, so skip the next iteration */ + ++row_idx; + } + } +} + +template +void as_waksman_routing_gadget::generate_r1cs_witness(const integer_permutation& permutation) +{ + /* pack inputs */ + for (size_t packet_idx = 0; packet_idx < num_packets; ++packet_idx) + { + pack_inputs[packet_idx].generate_r1cs_witness_from_bits(); + } + + /* do the routing */ + as_waksman_routing routing = get_as_waksman_routing(permutation); + + for (size_t column_idx = 0; column_idx < num_columns; ++column_idx) + { + for (size_t row_idx = 0; row_idx < num_packets; ++row_idx) + { + if (neighbors[column_idx][row_idx].first == neighbors[column_idx][row_idx].second) + { + /* this is a straight edge, so just pass the values forward */ + const size_t next = neighbors[column_idx][row_idx].first; + + for (size_t subpacket_idx = 0; subpacket_idx < num_subpackets; ++subpacket_idx) + { + this->pb.val(routed_packets[column_idx+1][next][subpacket_idx]) = this->pb.val(routed_packets[column_idx][row_idx][subpacket_idx]); + } + } + else + { + if (num_subpackets > 1) + { + /* update the switch bit */ + this->pb.val(asw_switch_bits[column_idx][row_idx]) = FieldT(routing[column_idx][row_idx] ? 1 : 0); + } + + /* route according to the switch bit */ + const bool switch_val = routing[column_idx][row_idx]; + + for (size_t switch_input : { row_idx, row_idx+1 }) + { + const size_t straight_edge = neighbors[column_idx][switch_input].first; + const size_t cross_edge = neighbors[column_idx][switch_input].second; + + const size_t switched_edge = (switch_val ? cross_edge : straight_edge); + + for (size_t subpacket_idx = 0; subpacket_idx < num_subpackets; ++subpacket_idx) + { + this->pb.val(routed_packets[column_idx+1][switched_edge][subpacket_idx]) = this->pb.val(routed_packets[column_idx][switch_input][subpacket_idx]); + } + } + + /* we processed both switch inputs at once, so skip the next iteration */ + ++row_idx; + } + } + } + + /* unpack outputs */ + for (size_t packet_idx = 0; packet_idx < num_packets; ++packet_idx) + { + unpack_outputs[packet_idx].generate_r1cs_witness_from_packed(); + } +} + +template +void test_as_waksman_routing_gadget(const size_t num_packets, const size_t packet_size) +{ + printf("testing as_waksman_routing_gadget by routing %zu element vector of %zu bits (Fp fits all %zu bit integers)\n", num_packets, packet_size, FieldT::capacity()); + protoboard pb; + integer_permutation permutation(num_packets); + permutation.random_shuffle(); + print_time("generated permutation"); + + std::vector > randbits(num_packets), outbits(num_packets); + for (size_t packet_idx = 0; packet_idx < num_packets; ++packet_idx) + { + randbits[packet_idx].allocate(pb, packet_size, FMT("", "randbits_%zu", packet_idx)); + outbits[packet_idx].allocate(pb, packet_size, FMT("", "outbits_%zu", packet_idx)); + + for (size_t bit_idx = 0; bit_idx < packet_size; ++bit_idx) + { + pb.val(randbits[packet_idx][bit_idx]) = (rand() % 2) ? FieldT::one() : FieldT::zero(); + } + } + print_time("generated bits to be routed"); + + as_waksman_routing_gadget r(pb, num_packets, randbits, outbits, "main_routing_gadget"); + r.generate_r1cs_constraints(); + print_time("generated routing constraints"); + + r.generate_r1cs_witness(permutation); + print_time("generated routing assignment"); + + printf("positive test\n"); + assert(pb.is_satisfied()); + for (size_t packet_idx = 0; packet_idx < num_packets; ++packet_idx) + { + for (size_t bit_idx = 0; bit_idx < packet_size; ++bit_idx) + { + assert(pb.val(outbits[permutation.get(packet_idx)][bit_idx]) == pb.val(randbits[packet_idx][bit_idx])); + } + } + + printf("negative test\n"); + pb.val(pb_variable(10)) = FieldT(12345); + assert(!pb.is_satisfied()); + + printf("num_constraints = %zu, num_variables = %zu\n", + pb.num_constraints(), + pb.constraint_system.num_variables); +} + +} // libsnark + +#endif // AS_WAKSMAN_ROUTING_GADGET_TCC_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/routing/benes_routing_gadget.hpp b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/routing/benes_routing_gadget.hpp new file mode 100644 index 0000000..5d4edb4 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/routing/benes_routing_gadget.hpp @@ -0,0 +1,81 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for the Benes routing gadget. + + The gadget verifies that the outputs are a permutation of the inputs, + by use of a Benes network. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef BENES_ROUTING_GADGET_HPP_ +#define BENES_ROUTING_GADGET_HPP_ + +#include "common/data_structures/integer_permutation.hpp" +#include "common/routing_algorithms/benes_routing_algorithm.hpp" +#include "gadgetlib1/gadgets/basic_gadgets.hpp" +#include "gadgetlib1/protoboard.hpp" + +namespace libsnark { + +template +class benes_routing_gadget : public gadget { +private: + /* + Indexing conventions: + + routed_packets[column_idx][packet_idx][subpacket_idx] + pack_inputs/unpack_outputs[packet_idx] + benes_switch_bits[column_idx][row_idx] + + Where column_idx ranges is in range 0 .. 2*dimension + (2*dimension-1 for switch bits/topology) and packet_idx is in + range 0 .. num_packets-1. + */ + std::vector > > routed_packets; + std::vector > pack_inputs, unpack_outputs; + + /* + If #packets = 1 then we can route without explicit routing bits + (and save half the constraints); in this case benes_switch_bits will + be unused. + + For benes_switch_bits 0 corresponds to straight edge and 1 + corresponds to cross edge. + */ + std::vector> benes_switch_bits; + benes_topology neighbors; +public: + const size_t num_packets; + const size_t num_columns; + + const std::vector > routing_input_bits; + const std::vector > routing_output_bits; + size_t lines_to_unpack; + + const size_t packet_size, num_subpackets; + + benes_routing_gadget(protoboard &pb, + const size_t num_packets, + const std::vector> &routing_input_bits, + const std::vector> &routing_output_bits, + const size_t lines_to_unpack, + const std::string& annotation_prefix=""); + + void generate_r1cs_constraints(); + + void generate_r1cs_witness(const integer_permutation &permutation); +}; + +template +void test_benes_routing_gadget(const size_t num_packets, const size_t packet_size); + +} // libsnark + +#include "gadgetlib1/gadgets/routing/benes_routing_gadget.tcc" + +#endif // BENES_ROUTING_GADGET_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/routing/benes_routing_gadget.tcc b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/routing/benes_routing_gadget.tcc new file mode 100644 index 0000000..cde9492 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/routing/benes_routing_gadget.tcc @@ -0,0 +1,247 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for the Benes routing gadget. + + See benes_routing_gadget.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef BENES_ROUTING_GADGET_TCC_ +#define BENES_ROUTING_GADGET_TCC_ + +#include "common/profiling.hpp" + +#include + +namespace libsnark { + +template +benes_routing_gadget::benes_routing_gadget(protoboard &pb, + const size_t num_packets, + const std::vector > &routing_input_bits, + const std::vector > &routing_output_bits, + const size_t lines_to_unpack, + const std::string& annotation_prefix) : + gadget(pb, annotation_prefix), + num_packets(num_packets), + num_columns(benes_num_columns(num_packets)), + routing_input_bits(routing_input_bits), + routing_output_bits(routing_output_bits), + lines_to_unpack(lines_to_unpack), + packet_size(routing_input_bits[0].size()), + num_subpackets(div_ceil(packet_size, FieldT::capacity())) +{ + assert(lines_to_unpack <= routing_input_bits.size()); + assert(num_packets == 1ul<(pb, + pb_variable_array(routing_input_bits[packet_idx].begin(), routing_input_bits[packet_idx].end()), + routed_packets[0][packet_idx], + FieldT::capacity(), + FMT(this->annotation_prefix, " pack_inputs_%zu", packet_idx))); + if (packet_idx < lines_to_unpack) + { + unpack_outputs.emplace_back( + multipacking_gadget(pb, + pb_variable_array(routing_output_bits[packet_idx].begin(), routing_output_bits[packet_idx].end()), + routed_packets[num_columns][packet_idx], + FieldT::capacity(), + FMT(this->annotation_prefix, " unpack_outputs_%zu", packet_idx))); + } + } + + if (num_subpackets > 1) + { + benes_switch_bits.resize(num_columns); + for (size_t column_idx = 0; column_idx < num_columns; ++column_idx) + { + benes_switch_bits[column_idx].allocate(pb, num_packets, FMT(this->annotation_prefix, " benes_switch_bits_%zu", column_idx)); + } + } +} + +template +void benes_routing_gadget::generate_r1cs_constraints() +{ + /* packing/unpacking */ + for (size_t packet_idx = 0; packet_idx < num_packets; ++packet_idx) + { + pack_inputs[packet_idx].generate_r1cs_constraints(false); + if (packet_idx < lines_to_unpack) + { + unpack_outputs[packet_idx].generate_r1cs_constraints(true); + } + else + { + for (size_t subpacket_idx = 0; subpacket_idx < num_subpackets; ++subpacket_idx) + { + this->pb.add_r1cs_constraint( + r1cs_constraint(1, routed_packets[0][packet_idx][subpacket_idx], routed_packets[num_columns][packet_idx][subpacket_idx]), + FMT(this->annotation_prefix, " fix_line_%zu_subpacket_%zu", packet_idx, subpacket_idx)); + } + } + } + + /* actual routing constraints */ + for (size_t column_idx = 0; column_idx < num_columns; ++column_idx) + { + for (size_t packet_idx = 0; packet_idx < num_packets; ++packet_idx) + { + const size_t straight_edge = neighbors[column_idx][packet_idx].first; + const size_t cross_edge = neighbors[column_idx][packet_idx].second; + + if (num_subpackets == 1) + { + /* easy case: (cur-next)*(cur-cross) = 0 */ + this->pb.add_r1cs_constraint( + r1cs_constraint( + routed_packets[column_idx][packet_idx][0] - routed_packets[column_idx+1][straight_edge][0], + routed_packets[column_idx][packet_idx][0] - routed_packets[column_idx+1][cross_edge][0], + 0), + FMT(this->annotation_prefix, " easy_route_%zu_%zu", column_idx, packet_idx)); + } + else + { + /* routing bit must be boolean */ + generate_boolean_r1cs_constraint(this->pb, benes_switch_bits[column_idx][packet_idx], + FMT(this->annotation_prefix, " routing_bit_%zu_%zu", column_idx, packet_idx)); + + /* route forward according to routing bits */ + for (size_t subpacket_idx = 0; subpacket_idx < num_subpackets; ++subpacket_idx) + { + /* + (1-switch_bit) * (cur-straight_edge) + switch_bit * (cur-cross_edge) = 0 + switch_bit * (cross_edge-straight_edge) = cur-straight_edge + */ + this->pb.add_r1cs_constraint( + r1cs_constraint( + benes_switch_bits[column_idx][packet_idx], + routed_packets[column_idx+1][cross_edge][subpacket_idx] - routed_packets[column_idx+1][straight_edge][subpacket_idx], + routed_packets[column_idx][packet_idx][subpacket_idx] - routed_packets[column_idx+1][straight_edge][subpacket_idx]), + FMT(this->annotation_prefix, " route_forward_%zu_%zu_%zu", column_idx, packet_idx, subpacket_idx)); + } + } + } + } +} + +template +void benes_routing_gadget::generate_r1cs_witness(const integer_permutation& permutation) +{ + /* pack inputs */ + for (size_t packet_idx = 0; packet_idx < num_packets; ++packet_idx) + { + pack_inputs[packet_idx].generate_r1cs_witness_from_bits(); + } + + /* do the routing */ + const benes_routing routing = get_benes_routing(permutation); + + for (size_t column_idx = 0; column_idx < num_columns; ++column_idx) + { + for (size_t packet_idx = 0; packet_idx < num_packets; ++packet_idx) + { + const size_t straight_edge = neighbors[column_idx][packet_idx].first; + const size_t cross_edge = neighbors[column_idx][packet_idx].second; + + if (num_subpackets > 1) + { + this->pb.val(benes_switch_bits[column_idx][packet_idx]) = FieldT(routing[column_idx][packet_idx] ? 1 : 0); + } + + for (size_t subpacket_idx = 0; subpacket_idx < num_subpackets; ++subpacket_idx) + { + this->pb.val(routing[column_idx][packet_idx] ? + routed_packets[column_idx+1][cross_edge][subpacket_idx] : + routed_packets[column_idx+1][straight_edge][subpacket_idx]) = + this->pb.val(routed_packets[column_idx][packet_idx][subpacket_idx]); + } + } + } + + /* unpack outputs */ + for (size_t packet_idx = 0; packet_idx < lines_to_unpack; ++packet_idx) + { + unpack_outputs[packet_idx].generate_r1cs_witness_from_packed(); + } +} + +template +void test_benes_routing_gadget(const size_t num_packets, const size_t packet_size) +{ + const size_t dimension = log2(num_packets); + assert(num_packets == 1ul< pb; + integer_permutation permutation(num_packets); + permutation.random_shuffle(); + print_time("generated permutation"); + + std::vector > randbits(num_packets), outbits(num_packets); + for (size_t packet_idx = 0; packet_idx < num_packets; ++packet_idx) + { + randbits[packet_idx].allocate(pb, packet_size, FMT("", "randbits_%zu", packet_idx)); + outbits[packet_idx].allocate(pb, packet_size, FMT("", "outbits_%zu", packet_idx)); + + for (size_t bit_idx = 0; bit_idx < packet_size; ++bit_idx) + { + pb.val(randbits[packet_idx][bit_idx]) = (rand() % 2) ? FieldT::one() : FieldT::zero(); + } + } + print_time("generated bits to be routed"); + + benes_routing_gadget r(pb, num_packets, randbits, outbits, num_packets, "main_routing_gadget"); + r.generate_r1cs_constraints(); + print_time("generated routing constraints"); + + r.generate_r1cs_witness(permutation); + print_time("generated routing assignment"); + + printf("positive test\n"); + assert(pb.is_satisfied()); + for (size_t packet_idx = 0; packet_idx < num_packets; ++packet_idx) + { + for (size_t bit_idx = 0; bit_idx < packet_size; ++bit_idx) + { + assert(pb.val(outbits[permutation.get(packet_idx)][bit_idx]) == pb.val(randbits[packet_idx][bit_idx])); + } + } + + printf("negative test\n"); + pb.val(pb_variable(10)) = FieldT(12345); + assert(!pb.is_satisfied()); + + printf("num_constraints = %zu, num_variables = %zu\n", + pb.num_constraints(), + pb.constraint_system.num_variables); +} + +} // libsnark + +#endif // BENES_ROUTING_GADGET_TCC_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/routing/profiling/profile_routing_gadgets.cpp b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/routing/profiling/profile_routing_gadgets.cpp new file mode 100644 index 0000000..2ff21cf --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/routing/profiling/profile_routing_gadgets.cpp @@ -0,0 +1,107 @@ +/** @file + ***************************************************************************** + + Functions to profile the gadgetlib1 implementations of Benes and AS-Waksman routing networks. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include + +#include "common/default_types/ec_pp.hpp" +#include "common/profiling.hpp" +#include "gadgetlib1/gadgets/routing/benes_routing_gadget.hpp" +#include "gadgetlib1/gadgets/routing/as_waksman_routing_gadget.hpp" + +using namespace libsnark; + +template +void get_as_waksman_size(const size_t n, const size_t l, size_t &num_constraints, size_t &num_variables) +{ + protoboard pb; + + std::vector > randbits(n), outbits(n); + for (size_t y = 0; y < n; ++y) + { + randbits[y].allocate(pb, l, FMT("", "randbits_%zu", y)); + outbits[y].allocate(pb, l, FMT("", "outbits_%zu", y)); + } + + as_waksman_routing_gadget r(pb, n, randbits, outbits, "main_routing_gadget"); + r.generate_r1cs_constraints(); + + num_constraints = pb.num_constraints(); + num_variables = pb.num_variables(); +} + +template +void get_benes_size(const size_t n, const size_t l, size_t &num_constraints, size_t &num_variables) +{ + const size_t t = log2(n); + assert(n == 1ul< pb; + + std::vector > randbits(1ul< r(pb, n, randbits, outbits, n, "main_routing_gadget"); + r.generate_r1cs_constraints(); + + num_constraints = pb.num_constraints(); + num_variables = pb.num_variables(); +} + +template +void profile_routing_gadgets(const size_t l) +{ + printf("profiling number of constraints for powers-of-2\n"); + for (size_t n = 2; n <= 65; ++n) + { + size_t as_waksman_constr, as_waksman_vars; + get_as_waksman_size(n, l, as_waksman_constr, as_waksman_vars); + + const size_t rounded_n = 1ul<(rounded_n, l, benes_constr, benes_vars); + + printf("n = %zu (rounded = %zu), l = %zu, benes_constr = %zu, benes_vars = %zu, as_waksman_constr = %zu, as_waksman_vars = %zu, constr_ratio = %0.3f, var_ratio = %0.3f\n", + n, rounded_n, l, benes_constr, benes_vars, as_waksman_constr, as_waksman_vars, 1.*benes_constr/as_waksman_constr, 1.*benes_vars/as_waksman_vars); + } +} + +template +void profile_num_switches(const size_t l) +{ + printf("profiling number of switches in arbitrary size networks (and rounded-up for Benes)\n"); + for (size_t n = 2; n <= 65; ++n) + { + size_t as_waksman_constr, as_waksman_vars; + get_as_waksman_size(n, l, as_waksman_constr, as_waksman_vars); + + const size_t rounded_n = 1ul<(rounded_n, l, benes_constr, benes_vars); + + const size_t as_waksman_switches = (as_waksman_constr - n*(2+l))/2; + const size_t benes_switches = (benes_constr - rounded_n*(2+l))/2; + // const size_t benes_expected = log2(rounded_n)*rounded_n; // switch-Benes has (-rounded_n/2) term + printf("n = %zu (rounded_n = %zu), l = %zu, benes_switches = %zu, as_waksman_switches = %zu, ratio = %0.3f\n", + n, rounded_n, l, benes_switches, as_waksman_switches, 1.*benes_switches/as_waksman_switches); + } +} + +int main() +{ + start_profiling(); + default_ec_pp::init_public_params(); + profile_routing_gadgets >(32+16+3+2); + profile_num_switches >(1); +} diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/set_commitment/set_commitment_gadget.hpp b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/set_commitment/set_commitment_gadget.hpp new file mode 100644 index 0000000..faafa07 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/set_commitment/set_commitment_gadget.hpp @@ -0,0 +1,57 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ +#ifndef SET_COMMITMENT_GADGET_HPP_ +#define SET_COMMITMENT_GADGET_HPP_ + +#include "gadgetlib1/gadget.hpp" +#include "gadgetlib1/gadgets/basic_gadgets.hpp" +#include "gadgetlib1/gadgets/hashes/hash_io.hpp" +#include "gadgetlib1/gadgets/merkle_tree/merkle_tree_check_read_gadget.hpp" +#include "gadgetlib1/gadgets/set_commitment/set_membership_proof_variable.hpp" + +namespace libsnark { + +template +using set_commitment_variable = digest_variable; + +template +class set_commitment_gadget : public gadget { +private: + std::shared_ptr > element_block; + std::shared_ptr > element_digest; + std::shared_ptr hash_element; + std::shared_ptr > check_membership; + +public: + size_t tree_depth; + pb_variable_array element_bits; + set_commitment_variable root_digest; + set_membership_proof_variable proof; + pb_linear_combination check_successful; + + set_commitment_gadget(protoboard &pb, + const size_t max_entries, + const pb_variable_array &element_bits, + const set_commitment_variable &root_digest, + const set_membership_proof_variable &proof, + const pb_linear_combination &check_successful, + const std::string &annotation_prefix); + + void generate_r1cs_constraints(); + void generate_r1cs_witness(); + + static size_t root_size_in_bits(); +}; + +template +void test_set_commitment_gadget(); + +} // libsnark + +#include "gadgetlib1/gadgets/set_commitment/set_commitment_gadget.tcc" + +#endif // SET_COMMITMENT_GADGET_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/set_commitment/set_commitment_gadget.tcc b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/set_commitment/set_commitment_gadget.tcc new file mode 100644 index 0000000..97f8290 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/set_commitment/set_commitment_gadget.tcc @@ -0,0 +1,141 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ +#ifndef SET_COMMITMENT_GADGET_TCC_ +#define SET_COMMITMENT_GADGET_TCC_ + +#include "common/data_structures/set_commitment.hpp" + +namespace libsnark { + +template +set_commitment_gadget::set_commitment_gadget(protoboard &pb, + const size_t max_entries, + const pb_variable_array &element_bits, + const set_commitment_variable &root_digest, + const set_membership_proof_variable &proof, + const pb_linear_combination &check_successful, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), tree_depth(log2(max_entries)), element_bits(element_bits), + root_digest(root_digest), proof(proof), check_successful(check_successful) +{ + element_block.reset(new block_variable(pb, { element_bits }, FMT(annotation_prefix, " element_block"))); + + if (tree_depth == 0) + { + hash_element.reset(new HashT(pb, element_bits.size(), *element_block, root_digest, FMT(annotation_prefix, " hash_element"))); + } + else + { + element_digest.reset(new digest_variable(pb, HashT::get_digest_len(), + FMT(annotation_prefix, " element_digest"))); + hash_element.reset(new HashT(pb, element_bits.size(), *element_block, *element_digest, FMT(annotation_prefix, " hash_element"))); + check_membership.reset(new merkle_tree_check_read_gadget(pb, + tree_depth, + proof.address_bits, + *element_digest, + root_digest, + *proof.merkle_path, + check_successful, + FMT(annotation_prefix, " check_membership"))); + } +} + +template +void set_commitment_gadget::generate_r1cs_constraints() +{ + hash_element->generate_r1cs_constraints(); + + if (tree_depth > 0) + { + check_membership->generate_r1cs_constraints(); + } +} + +template +void set_commitment_gadget::generate_r1cs_witness() +{ + hash_element->generate_r1cs_witness(); + + if (tree_depth > 0) + { + check_membership->generate_r1cs_witness(); + } +} + +template +size_t set_commitment_gadget::root_size_in_bits() +{ + return merkle_tree_check_read_gadget::root_size_in_bits(); +} + +template +void test_set_commitment_gadget() +{ + const size_t digest_len = HashT::get_digest_len(); + const size_t max_set_size = 16; + const size_t value_size = (HashT::get_block_len() > 0 ? HashT::get_block_len() : 10); + + set_commitment_accumulator accumulator(max_set_size, value_size); + + std::vector set_elems; + for (size_t i = 0; i < max_set_size; ++i) + { + bit_vector elem(value_size); + std::generate(elem.begin(), elem.end(), [&]() { return std::rand() % 2; }); + set_elems.emplace_back(elem); + accumulator.add(elem); + assert(accumulator.is_in_set(elem)); + } + + protoboard pb; + pb_variable_array element_bits; + element_bits.allocate(pb, value_size, "element_bits"); + set_commitment_variable root_digest(pb, digest_len, "root_digest"); + + pb_variable check_succesful; + check_succesful.allocate(pb, "check_succesful"); + + set_membership_proof_variable proof(pb, max_set_size, "proof"); + + set_commitment_gadget sc(pb, max_set_size, element_bits, root_digest, proof, check_succesful, "sc"); + sc.generate_r1cs_constraints(); + + /* test all elements from set */ + for (size_t i = 0; i < max_set_size; ++i) + { + element_bits.fill_with_bits(pb, set_elems[i]); + pb.val(check_succesful) = FieldT::one(); + proof.generate_r1cs_witness(accumulator.get_membership_proof(set_elems[i])); + sc.generate_r1cs_witness(); + root_digest.generate_r1cs_witness(accumulator.get_commitment()); + assert(pb.is_satisfied()); + } + printf("membership tests OK\n"); + + /* test an element not in set */ + for (size_t i = 0; i < value_size; ++i) + { + pb.val(element_bits[i]) = FieldT(std::rand() % 2); + } + + pb.val(check_succesful) = FieldT::zero(); /* do not require the check result to be successful */ + proof.generate_r1cs_witness(accumulator.get_membership_proof(set_elems[0])); /* try it with invalid proof */ + sc.generate_r1cs_witness(); + root_digest.generate_r1cs_witness(accumulator.get_commitment()); + assert(pb.is_satisfied()); + + pb.val(check_succesful) = FieldT::one(); /* now require the check result to be succesful */ + proof.generate_r1cs_witness(accumulator.get_membership_proof(set_elems[0])); /* try it with invalid proof */ + sc.generate_r1cs_witness(); + root_digest.generate_r1cs_witness(accumulator.get_commitment()); + assert(!pb.is_satisfied()); /* the protoboard should be unsatisfied */ + printf("non-membership test OK\n"); +} + +} // libsnark + +#endif // SET_COMMITMENT_GADGET_TCC_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/set_commitment/set_membership_proof_variable.hpp b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/set_commitment/set_membership_proof_variable.hpp new file mode 100644 index 0000000..4aa9a02 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/set_commitment/set_membership_proof_variable.hpp @@ -0,0 +1,43 @@ +/** + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef SET_MEMBERSHIP_PROOF_VARIABLE_HPP_ +#define SET_MEMBERSHIP_PROOF_VARIABLE_HPP_ + +#include "common/data_structures/set_commitment.hpp" +#include "gadgetlib1/gadget.hpp" +#include "gadgetlib1/gadgets/hashes/hash_io.hpp" +#include "gadgetlib1/gadgets/merkle_tree/merkle_authentication_path_variable.hpp" + +namespace libsnark { + +template +class set_membership_proof_variable : public gadget { +public: + pb_variable_array address_bits; + std::shared_ptr > merkle_path; + + const size_t max_entries; + const size_t tree_depth; + + set_membership_proof_variable(protoboard &pb, + const size_t max_entries, + const std::string &annotation_prefix); + + void generate_r1cs_constraints(); + void generate_r1cs_witness(const set_membership_proof &proof); + + set_membership_proof get_membership_proof() const; + + static r1cs_variable_assignment as_r1cs_variable_assignment(const set_membership_proof &proof); +}; + +} // libsnark + +#include "gadgetlib1/gadgets/set_commitment/set_membership_proof_variable.tcc" + +#endif // SET_MEMBERSHIP_PROOF_VARIABLE_HPP diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/set_commitment/set_membership_proof_variable.tcc b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/set_commitment/set_membership_proof_variable.tcc new file mode 100644 index 0000000..6a77550 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/set_commitment/set_membership_proof_variable.tcc @@ -0,0 +1,82 @@ +/** + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef SET_MEMBERSHIP_PROOF_VARIABLE_TCC_ +#define SET_MEMBERSHIP_PROOF_VARIABLE_TCC_ + +namespace libsnark { + +template +set_membership_proof_variable::set_membership_proof_variable(protoboard &pb, + const size_t max_entries, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), + max_entries(max_entries), + tree_depth(log2(max_entries)) +{ + if (tree_depth > 0) + { + address_bits.allocate(pb, tree_depth, FMT(annotation_prefix, " address_bits")); + merkle_path.reset(new merkle_authentication_path_variable(pb, tree_depth, FMT(annotation_prefix, " merkle_path"))); + } +} + +template +void set_membership_proof_variable::generate_r1cs_constraints() +{ + if (tree_depth > 0) + { + for (size_t i = 0; i < tree_depth; ++i) + { + generate_boolean_r1cs_constraint(this->pb, address_bits[i], FMT(this->annotation_prefix, " address_bits")); + } + merkle_path->generate_r1cs_constraints(); + } +} + +template +void set_membership_proof_variable::generate_r1cs_witness(const set_membership_proof &proof) +{ + if (tree_depth > 0) + { + address_bits.fill_with_bits_of_field_element(this->pb, FieldT(proof.address)); + merkle_path->generate_r1cs_witness(proof.address, proof.merkle_path); + } +} + +template +set_membership_proof set_membership_proof_variable::get_membership_proof() const +{ + set_membership_proof result; + + if (tree_depth == 0) + { + result.address = 0; + } + else + { + result.address = address_bits.get_field_element_from_bits(this->pb).as_ulong(); + result.merkle_path = merkle_path->get_authentication_path(result.address); + } + + return result; +} + +template +r1cs_variable_assignment set_membership_proof_variable::as_r1cs_variable_assignment(const set_membership_proof &proof) +{ + protoboard pb; + const size_t max_entries = (1ul << (proof.merkle_path.size())); + set_membership_proof_variable proof_variable(pb, max_entries, "proof_variable"); + proof_variable.generate_r1cs_witness(proof); + + return pb.full_variable_assignment(); +} + +} // libsnark + +#endif // SET_MEMBERSHIP_PROOF_VARIABLE_TCC diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/set_commitment/tests/test_set_commitment_gadget.cpp b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/set_commitment/tests/test_set_commitment_gadget.cpp new file mode 100644 index 0000000..ef9f7ea --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/set_commitment/tests/test_set_commitment_gadget.cpp @@ -0,0 +1,44 @@ +/** + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifdef CURVE_BN128 +#include "algebra/curves/bn128/bn128_pp.hpp" +#endif +#include "algebra/curves/edwards/edwards_pp.hpp" +#include "algebra/curves/mnt/mnt4/mnt4_pp.hpp" +#include "algebra/curves/mnt/mnt6/mnt6_pp.hpp" +#include "gadgetlib1/gadgets/set_commitment/set_commitment_gadget.hpp" +#include "gadgetlib1/gadgets/hashes/sha256/sha256_gadget.hpp" + +using namespace libsnark; + +template +void test_all_set_commitment_gadgets() +{ + typedef Fr FieldT; + test_set_commitment_gadget >(); + test_set_commitment_gadget >(); +} + +int main(void) +{ + start_profiling(); + +#ifdef CURVE_BN128 // BN128 has fancy dependencies so it may be disabled + bn128_pp::init_public_params(); + test_all_set_commitment_gadgets(); +#endif + + edwards_pp::init_public_params(); + test_all_set_commitment_gadgets(); + + mnt4_pp::init_public_params(); + test_all_set_commitment_gadgets(); + + mnt6_pp::init_public_params(); + test_all_set_commitment_gadgets(); +} diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/verifiers/r1cs_ppzksnark_verifier_gadget.hpp b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/verifiers/r1cs_ppzksnark_verifier_gadget.hpp new file mode 100644 index 0000000..f92cb5b --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/verifiers/r1cs_ppzksnark_verifier_gadget.hpp @@ -0,0 +1,250 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for the the R1CS ppzkSNARK verifier gadget. + + The gadget r1cs_ppzksnark_verifier_gadget verifiers correct computation of r1cs_ppzksnark_verifier_strong_IC. + The gadget is built from two main sub-gadgets: + - r1cs_ppzksnark_verifier_process_vk_gadget, which verifies correct computation of r1cs_ppzksnark_verifier_process_vk, and + - r1cs_ppzksnark_online_verifier_gadget, which verifies correct computation of r1cs_ppzksnark_online_verifier_strong_IC. + See r1cs_ppzksnark.hpp for description of the aforementioned functions. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef R1CS_PPZKSNARK_VERIFIER_GADGET_HPP_ +#define R1CS_PPZKSNARK_VERIFIER_GADGET_HPP_ + +#include "gadgetlib1/gadgets/basic_gadgets.hpp" +#include "gadgetlib1/gadgets/curves/weierstrass_g1_gadget.hpp" +#include "gadgetlib1/gadgets/curves/weierstrass_g2_gadget.hpp" +#include "gadgetlib1/gadgets/pairing/pairing_checks.hpp" +#include "gadgetlib1/gadgets/pairing/pairing_params.hpp" +#include "zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.hpp" + +namespace libsnark { + +template +class r1cs_ppzksnark_proof_variable : public gadget > { +public: + typedef Fr FieldT; + + std::shared_ptr > g_A_g; + std::shared_ptr > g_A_h; + std::shared_ptr > g_B_g; + std::shared_ptr > g_B_h; + std::shared_ptr > g_C_g; + std::shared_ptr > g_C_h; + std::shared_ptr > g_H; + std::shared_ptr > g_K; + + std::vector > > all_G1_vars; + std::vector > > all_G2_vars; + + std::vector > > all_G1_checkers; + std::shared_ptr > G2_checker; + + pb_variable_array proof_contents; + + r1cs_ppzksnark_proof_variable(protoboard &pb, + const std::string &annotation_prefix); + void generate_r1cs_constraints(); + void generate_r1cs_witness(const r1cs_ppzksnark_proof > &proof); + static size_t size(); +}; + +template +class r1cs_ppzksnark_verification_key_variable : public gadget > { +public: + typedef Fr FieldT; + + std::shared_ptr > alphaA_g2; + std::shared_ptr > alphaB_g1; + std::shared_ptr > alphaC_g2; + std::shared_ptr > gamma_g2; + std::shared_ptr > gamma_beta_g1; + std::shared_ptr > gamma_beta_g2; + std::shared_ptr > rC_Z_g2; + std::shared_ptr > encoded_IC_base; + std::vector > > encoded_IC_query; + + pb_variable_array all_bits; + pb_linear_combination_array all_vars; + size_t input_size; + + std::vector > > all_G1_vars; + std::vector > > all_G2_vars; + + std::shared_ptr > packer; + + // Unfortunately, g++ 4.9 and g++ 5.0 have a bug related to + // incorrect inlining of small functions: + // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=65307, which + // produces wrong assembly even at -O1. The test case at the bug + // report is directly derived from this code here. As a temporary + // work-around we mark the key functions noinline to hint compiler + // that inlining should not be performed. + + // TODO: remove later, when g++ developers fix the bug. + + __attribute__((noinline)) r1cs_ppzksnark_verification_key_variable(protoboard &pb, + const pb_variable_array &all_bits, + const size_t input_size, + const std::string &annotation_prefix); + void generate_r1cs_constraints(const bool enforce_bitness); + void generate_r1cs_witness(const r1cs_ppzksnark_verification_key > &vk); + void generate_r1cs_witness(const bit_vector &vk_bits); + bit_vector get_bits() const; + static size_t __attribute__((noinline)) size_in_bits(const size_t input_size); + static bit_vector get_verification_key_bits(const r1cs_ppzksnark_verification_key > &r1cs_vk); +}; + +template +class r1cs_ppzksnark_preprocessed_r1cs_ppzksnark_verification_key_variable { +public: + typedef Fr FieldT; + + std::shared_ptr > encoded_IC_base; + std::vector > > encoded_IC_query; + + std::shared_ptr > vk_alphaB_g1_precomp; + std::shared_ptr > vk_gamma_beta_g1_precomp; + + std::shared_ptr > pp_G2_one_precomp; + std::shared_ptr > vk_alphaA_g2_precomp; + std::shared_ptr > vk_alphaC_g2_precomp; + std::shared_ptr > vk_gamma_beta_g2_precomp; + std::shared_ptr > vk_gamma_g2_precomp; + std::shared_ptr > vk_rC_Z_g2_precomp; + + r1cs_ppzksnark_preprocessed_r1cs_ppzksnark_verification_key_variable(); + r1cs_ppzksnark_preprocessed_r1cs_ppzksnark_verification_key_variable(protoboard &pb, + const r1cs_ppzksnark_verification_key > &r1cs_vk, + const std::string &annotation_prefix); +}; + +template +class r1cs_ppzksnark_verifier_process_vk_gadget : public gadget > { +public: + typedef Fr FieldT; + + std::shared_ptr > compute_vk_alphaB_g1_precomp; + std::shared_ptr > compute_vk_gamma_beta_g1_precomp; + + std::shared_ptr > compute_vk_alphaA_g2_precomp; + std::shared_ptr > compute_vk_alphaC_g2_precomp; + std::shared_ptr > compute_vk_gamma_beta_g2_precomp; + std::shared_ptr > compute_vk_gamma_g2_precomp; + std::shared_ptr > compute_vk_rC_Z_g2_precomp; + + r1cs_ppzksnark_verification_key_variable vk; + r1cs_ppzksnark_preprocessed_r1cs_ppzksnark_verification_key_variable &pvk; // important to have a reference here + + r1cs_ppzksnark_verifier_process_vk_gadget(protoboard &pb, + const r1cs_ppzksnark_verification_key_variable &vk, + r1cs_ppzksnark_preprocessed_r1cs_ppzksnark_verification_key_variable &pvk, + const std::string &annotation_prefix); + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +template +class r1cs_ppzksnark_online_verifier_gadget : public gadget > { +public: + typedef Fr FieldT; + + r1cs_ppzksnark_preprocessed_r1cs_ppzksnark_verification_key_variable pvk; + + pb_variable_array input; + size_t elt_size; + r1cs_ppzksnark_proof_variable proof; + pb_variable result; + const size_t input_len; + + std::shared_ptr > acc; + std::shared_ptr > accumulate_input; + + std::shared_ptr > proof_g_A_g_acc; + std::shared_ptr > compute_proof_g_A_g_acc; + std::shared_ptr > proof_g_A_g_acc_C; + std::shared_ptr > compute_proof_g_A_g_acc_C; + + std::shared_ptr > proof_g_A_h_precomp; + std::shared_ptr > proof_g_A_g_acc_C_precomp; + std::shared_ptr > proof_g_A_g_acc_precomp; + std::shared_ptr > proof_g_A_g_precomp; + std::shared_ptr > proof_g_B_h_precomp; + std::shared_ptr > proof_g_C_h_precomp; + std::shared_ptr > proof_g_C_g_precomp; + std::shared_ptr > proof_g_K_precomp; + std::shared_ptr > proof_g_H_precomp; + + std::shared_ptr > proof_g_B_g_precomp; + + std::shared_ptr > compute_proof_g_A_h_precomp; + std::shared_ptr > compute_proof_g_A_g_acc_C_precomp; + std::shared_ptr > compute_proof_g_A_g_acc_precomp; + std::shared_ptr > compute_proof_g_A_g_precomp; + std::shared_ptr > compute_proof_g_B_h_precomp; + std::shared_ptr > compute_proof_g_C_h_precomp; + std::shared_ptr > compute_proof_g_C_g_precomp; + std::shared_ptr > compute_proof_g_K_precomp; + std::shared_ptr > compute_proof_g_H_precomp; + + std::shared_ptr > compute_proof_g_B_g_precomp; + + std::shared_ptr > check_kc_A_valid; + std::shared_ptr > check_kc_B_valid; + std::shared_ptr > check_kc_C_valid; + std::shared_ptr > check_QAP_valid; + std::shared_ptr > check_CC_valid; + + pb_variable kc_A_valid; + pb_variable kc_B_valid; + pb_variable kc_C_valid; + pb_variable QAP_valid; + pb_variable CC_valid; + + pb_variable_array all_test_results; + std::shared_ptr > all_tests_pass; + + r1cs_ppzksnark_online_verifier_gadget(protoboard &pb, + const r1cs_ppzksnark_preprocessed_r1cs_ppzksnark_verification_key_variable &pvk, + const pb_variable_array &input, + const size_t elt_size, + const r1cs_ppzksnark_proof_variable &proof, + const pb_variable &result, + const std::string &annotation_prefix); + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +template +class r1cs_ppzksnark_verifier_gadget : public gadget > { +public: + typedef Fr FieldT; + + std::shared_ptr > pvk; + std::shared_ptr > compute_pvk; + std::shared_ptr > online_verifier; + + r1cs_ppzksnark_verifier_gadget(protoboard &pb, + const r1cs_ppzksnark_verification_key_variable &vk, + const pb_variable_array &input, + const size_t elt_size, + const r1cs_ppzksnark_proof_variable &proof, + const pb_variable &result, + const std::string &annotation_prefix); + + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +} // libsnark + +#include "gadgetlib1/gadgets/verifiers/r1cs_ppzksnark_verifier_gadget.tcc" + +#endif // R1CS_PPZKSNARK_VERIFIER_GADGET_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/verifiers/r1cs_ppzksnark_verifier_gadget.tcc b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/verifiers/r1cs_ppzksnark_verifier_gadget.tcc new file mode 100644 index 0000000..f372fb6 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/verifiers/r1cs_ppzksnark_verifier_gadget.tcc @@ -0,0 +1,514 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for the the R1CS ppzkSNARK verifier gadget. + + See r1cs_ppzksnark_verifier_gadget.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef R1CS_PPZKSNARK_VERIFIER_GADGET_TCC_ +#define R1CS_PPZKSNARK_VERIFIER_GADGET_TCC_ + +#include "gadgetlib1/constraint_profiling.hpp" + +namespace libsnark { + +template +r1cs_ppzksnark_proof_variable::r1cs_ppzksnark_proof_variable(protoboard &pb, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix) +{ + const size_t num_G1 = 7; + const size_t num_G2 = 1; + + g_A_g.reset(new G1_variable(pb, FMT(annotation_prefix, " g_A_g"))); + g_A_h.reset(new G1_variable(pb, FMT(annotation_prefix, " g_A_h"))); + g_B_g.reset(new G2_variable(pb, FMT(annotation_prefix, " g_B_g"))); + g_B_h.reset(new G1_variable(pb, FMT(annotation_prefix, " g_B_h"))); + g_C_g.reset(new G1_variable(pb, FMT(annotation_prefix, " g_C_g"))); + g_C_h.reset(new G1_variable(pb, FMT(annotation_prefix, " g_C_h"))); + g_H.reset(new G1_variable(pb, FMT(annotation_prefix, " g_H"))); + g_K.reset(new G1_variable(pb, FMT(annotation_prefix, " g_K"))); + + all_G1_vars = { g_A_g, g_A_h, g_B_h, g_C_g, g_C_h, g_H,g_K }; + all_G2_vars = { g_B_g }; + + all_G1_checkers.resize(all_G1_vars.size()); + + for (size_t i = 0; i < all_G1_vars.size(); ++i) + { + all_G1_checkers[i].reset(new G1_checker_gadget(pb, *all_G1_vars[i], FMT(annotation_prefix, " all_G1_checkers_%zu", i))); + } + G2_checker.reset(new G2_checker_gadget(pb, *g_B_g, FMT(annotation_prefix, " G2_checker"))); + + assert(all_G1_vars.size() == num_G1); + assert(all_G2_vars.size() == num_G2); +} + +template +void r1cs_ppzksnark_proof_variable::generate_r1cs_constraints() +{ + for (auto &G1_checker : all_G1_checkers) + { + G1_checker->generate_r1cs_constraints(); + } + + G2_checker->generate_r1cs_constraints(); +} + +template +void r1cs_ppzksnark_proof_variable::generate_r1cs_witness(const r1cs_ppzksnark_proof > &proof) +{ + std::vector > > G1_elems; + std::vector > > G2_elems; + + G1_elems = { proof.g_A.g, proof.g_A.h, proof.g_B.h, proof.g_C.g, proof.g_C.h, proof.g_H, proof.g_K }; + G2_elems = { proof.g_B.g }; + + assert(G1_elems.size() == all_G1_vars.size()); + assert(G2_elems.size() == all_G2_vars.size()); + + for (size_t i = 0; i < G1_elems.size(); ++i) + { + all_G1_vars[i]->generate_r1cs_witness(G1_elems[i]); + } + + for (size_t i = 0; i < G2_elems.size(); ++i) + { + all_G2_vars[i]->generate_r1cs_witness(G2_elems[i]); + } + + for (auto &G1_checker : all_G1_checkers) + { + G1_checker->generate_r1cs_witness(); + } + + G2_checker->generate_r1cs_witness(); +} + +template +size_t r1cs_ppzksnark_proof_variable::size() +{ + const size_t num_G1 = 7; + const size_t num_G2 = 1; + return (num_G1 * G1_variable::num_field_elems + num_G2 * G2_variable::num_field_elems); +} + +template +r1cs_ppzksnark_verification_key_variable::r1cs_ppzksnark_verification_key_variable(protoboard &pb, + const pb_variable_array &all_bits, + const size_t input_size, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), + all_bits(all_bits), + input_size(input_size) +{ + const size_t num_G1 = 2 + (input_size + 1); + const size_t num_G2 = 5; + + assert(all_bits.size() == (G1_variable::size_in_bits() * num_G1 + G2_variable::size_in_bits() * num_G2)); + + this->alphaA_g2.reset(new G2_variable(pb, FMT(annotation_prefix, " alphaA_g2"))); + this->alphaB_g1.reset(new G1_variable(pb, FMT(annotation_prefix, " alphaB_g1"))); + this->alphaC_g2.reset(new G2_variable(pb, FMT(annotation_prefix, " alphaC_g2"))); + this->gamma_g2.reset(new G2_variable(pb, FMT(annotation_prefix, " gamma_g2"))); + this->gamma_beta_g1.reset(new G1_variable(pb, FMT(annotation_prefix, " gamma_beta_g1"))); + this->gamma_beta_g2.reset(new G2_variable(pb, FMT(annotation_prefix, " gamma_beta_g2"))); + this->rC_Z_g2.reset(new G2_variable(pb, FMT(annotation_prefix, " rC_Z_g2"))); + + all_G1_vars = { this->alphaB_g1, this->gamma_beta_g1 }; + all_G2_vars = { this->alphaA_g2, this->alphaC_g2, this->gamma_g2, this->gamma_beta_g2, this->rC_Z_g2 }; + + this->encoded_IC_query.resize(input_size); + this->encoded_IC_base.reset(new G1_variable(pb, FMT(annotation_prefix, " encoded_IC_base"))); + this->all_G1_vars.emplace_back(this->encoded_IC_base); + + for (size_t i = 0; i < input_size; ++i) + { + this->encoded_IC_query[i].reset(new G1_variable(pb, FMT(annotation_prefix, " encoded_IC_query_%zu", i))); + all_G1_vars.emplace_back(this->encoded_IC_query[i]); + } + + for (auto &G1_var : all_G1_vars) + { + all_vars.insert(all_vars.end(), G1_var->all_vars.begin(), G1_var->all_vars.end()); + } + + for (auto &G2_var : all_G2_vars) + { + all_vars.insert(all_vars.end(), G2_var->all_vars.begin(), G2_var->all_vars.end()); + } + + assert(all_G1_vars.size() == num_G1); + assert(all_G2_vars.size() == num_G2); + assert(all_vars.size() == (num_G1 * G1_variable::num_variables() + num_G2 * G2_variable::num_variables())); + + packer.reset(new multipacking_gadget(pb, all_bits, all_vars, FieldT::size_in_bits(), FMT(annotation_prefix, " packer"))); +} + +template +void r1cs_ppzksnark_verification_key_variable::generate_r1cs_constraints(const bool enforce_bitness) +{ + packer->generate_r1cs_constraints(enforce_bitness); +} + +template +void r1cs_ppzksnark_verification_key_variable::generate_r1cs_witness(const r1cs_ppzksnark_verification_key > &vk) +{ + std::vector > > G1_elems; + std::vector > > G2_elems; + + G1_elems = { vk.alphaB_g1, vk.gamma_beta_g1 }; + G2_elems = { vk.alphaA_g2, vk.alphaC_g2, vk.gamma_g2, vk.gamma_beta_g2, vk.rC_Z_g2 }; + + assert(vk.encoded_IC_query.rest.indices.size() == input_size); + G1_elems.emplace_back(vk.encoded_IC_query.first); + for (size_t i = 0; i < input_size; ++i) + { + assert(vk.encoded_IC_query.rest.indices[i] == i); + G1_elems.emplace_back(vk.encoded_IC_query.rest.values[i]); + } + + assert(G1_elems.size() == all_G1_vars.size()); + assert(G2_elems.size() == all_G2_vars.size()); + + for (size_t i = 0; i < G1_elems.size(); ++i) + { + all_G1_vars[i]->generate_r1cs_witness(G1_elems[i]); + } + + for (size_t i = 0; i < G2_elems.size(); ++i) + { + all_G2_vars[i]->generate_r1cs_witness(G2_elems[i]); + } + + packer->generate_r1cs_witness_from_packed(); +} + +template +void r1cs_ppzksnark_verification_key_variable::generate_r1cs_witness(const bit_vector &vk_bits) +{ + all_bits.fill_with_bits(this->pb, vk_bits); + packer->generate_r1cs_witness_from_bits(); +} + +template +bit_vector r1cs_ppzksnark_verification_key_variable::get_bits() const +{ + return all_bits.get_bits(this->pb); +} + +template +size_t r1cs_ppzksnark_verification_key_variable::size_in_bits(const size_t input_size) +{ + const size_t num_G1 = 2 + (input_size + 1); + const size_t num_G2 = 5; + const size_t result = G1_variable::size_in_bits() * num_G1 + G2_variable::size_in_bits() * num_G2; + printf("G1_size_in_bits = %zu, G2_size_in_bits = %zu\n", G1_variable::size_in_bits(), G2_variable::size_in_bits()); + printf("r1cs_ppzksnark_verification_key_variable::size_in_bits(%zu) = %zu\n", input_size, result); + return result; +} + +template +bit_vector r1cs_ppzksnark_verification_key_variable::get_verification_key_bits(const r1cs_ppzksnark_verification_key > &r1cs_vk) +{ + typedef Fr FieldT; + + const size_t input_size_in_elts = r1cs_vk.encoded_IC_query.rest.indices.size(); // this might be approximate for bound verification keys, however they are not supported by r1cs_ppzksnark_verification_key_variable + const size_t vk_size_in_bits = r1cs_ppzksnark_verification_key_variable::size_in_bits(input_size_in_elts); + + protoboard pb; + pb_variable_array vk_bits; + vk_bits.allocate(pb, vk_size_in_bits, "vk_bits"); + r1cs_ppzksnark_verification_key_variable vk(pb, vk_bits, input_size_in_elts, "translation_step_vk"); + vk.generate_r1cs_witness(r1cs_vk); + + return vk.get_bits(); +} + +template +r1cs_ppzksnark_preprocessed_r1cs_ppzksnark_verification_key_variable::r1cs_ppzksnark_preprocessed_r1cs_ppzksnark_verification_key_variable() +{ + // will be allocated outside +} + +template +r1cs_ppzksnark_preprocessed_r1cs_ppzksnark_verification_key_variable::r1cs_ppzksnark_preprocessed_r1cs_ppzksnark_verification_key_variable(protoboard &pb, + const r1cs_ppzksnark_verification_key > &r1cs_vk, + const std::string &annotation_prefix) +{ + encoded_IC_base.reset(new G1_variable(pb, r1cs_vk.encoded_IC_query.first, FMT(annotation_prefix, " encoded_IC_base"))); + encoded_IC_query.resize(r1cs_vk.encoded_IC_query.rest.indices.size()); + for (size_t i = 0; i < r1cs_vk.encoded_IC_query.rest.indices.size(); ++i) + { + assert(r1cs_vk.encoded_IC_query.rest.indices[i] == i); + encoded_IC_query[i].reset(new G1_variable(pb, r1cs_vk.encoded_IC_query.rest.values[i], FMT(annotation_prefix, " encoded_IC_query"))); + } + + vk_alphaB_g1_precomp.reset(new G1_precomputation(pb, r1cs_vk.alphaB_g1, FMT(annotation_prefix, " vk_alphaB_g1_precomp"))); + vk_gamma_beta_g1_precomp.reset(new G1_precomputation(pb, r1cs_vk.gamma_beta_g1, FMT(annotation_prefix, " vk_gamma_beta_g1_precomp"))); + + pp_G2_one_precomp.reset(new G2_precomputation(pb, G2 >::one(), FMT(annotation_prefix, " pp_G2_one_precomp"))); + vk_alphaA_g2_precomp.reset(new G2_precomputation(pb, r1cs_vk.alphaA_g2, FMT(annotation_prefix, " vk_alphaA_g2_precomp"))); + vk_alphaC_g2_precomp.reset(new G2_precomputation(pb, r1cs_vk.alphaC_g2, FMT(annotation_prefix, " vk_alphaC_g2_precomp"))); + vk_gamma_beta_g2_precomp.reset(new G2_precomputation(pb, r1cs_vk.gamma_beta_g2, FMT(annotation_prefix, " vk_gamma_beta_g2_precomp"))); + vk_gamma_g2_precomp.reset(new G2_precomputation(pb, r1cs_vk.gamma_g2, FMT(annotation_prefix, " vk_gamma_g2_precomp"))); + vk_rC_Z_g2_precomp.reset(new G2_precomputation(pb, r1cs_vk.rC_Z_g2, FMT(annotation_prefix, " vk_rC_Z_g2_precomp"))); +} + +template +r1cs_ppzksnark_verifier_process_vk_gadget::r1cs_ppzksnark_verifier_process_vk_gadget(protoboard &pb, + const r1cs_ppzksnark_verification_key_variable &vk, + r1cs_ppzksnark_preprocessed_r1cs_ppzksnark_verification_key_variable &pvk, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), + vk(vk), + pvk(pvk) +{ + pvk.encoded_IC_base = vk.encoded_IC_base; + pvk.encoded_IC_query = vk.encoded_IC_query; + + pvk.vk_alphaB_g1_precomp.reset(new G1_precomputation()); + pvk.vk_gamma_beta_g1_precomp.reset(new G1_precomputation()); + + pvk.pp_G2_one_precomp.reset(new G2_precomputation()); + pvk.vk_alphaA_g2_precomp.reset(new G2_precomputation()); + pvk.vk_alphaC_g2_precomp.reset(new G2_precomputation()); + pvk.vk_gamma_beta_g2_precomp.reset(new G2_precomputation()); + pvk.vk_gamma_g2_precomp.reset(new G2_precomputation()); + pvk.vk_rC_Z_g2_precomp.reset(new G2_precomputation()); + + compute_vk_alphaB_g1_precomp.reset(new precompute_G1_gadget(pb, *vk.alphaB_g1, *pvk.vk_alphaB_g1_precomp, FMT(annotation_prefix, " compute_vk_alphaB_g1_precomp"))); + compute_vk_gamma_beta_g1_precomp.reset(new precompute_G1_gadget(pb, *vk.gamma_beta_g1, *pvk.vk_gamma_beta_g1_precomp, FMT(annotation_prefix, " compute_vk_gamma_beta_g1_precomp"))); + + pvk.pp_G2_one_precomp.reset(new G2_precomputation(pb, G2 >::one(), FMT(annotation_prefix, " pp_G2_one_precomp"))); + compute_vk_alphaA_g2_precomp.reset(new precompute_G2_gadget(pb, *vk.alphaA_g2, *pvk.vk_alphaA_g2_precomp, FMT(annotation_prefix, " compute_vk_alphaA_g2_precomp"))); + compute_vk_alphaC_g2_precomp.reset(new precompute_G2_gadget(pb, *vk.alphaC_g2, *pvk.vk_alphaC_g2_precomp, FMT(annotation_prefix, " compute_vk_alphaC_g2_precomp"))); + compute_vk_gamma_beta_g2_precomp.reset(new precompute_G2_gadget(pb, *vk.gamma_beta_g2, *pvk.vk_gamma_beta_g2_precomp, FMT(annotation_prefix, " compute_vk_gamma_beta_g2_precomp"))); + compute_vk_gamma_g2_precomp.reset(new precompute_G2_gadget(pb, *vk.gamma_g2, *pvk.vk_gamma_g2_precomp, FMT(annotation_prefix, " compute_vk_gamma_g2_precomp"))); + compute_vk_rC_Z_g2_precomp.reset(new precompute_G2_gadget(pb, *vk.rC_Z_g2, *pvk.vk_rC_Z_g2_precomp, FMT(annotation_prefix, " compute_vk_rC_Z_g2_precomp"))); +} + +template +void r1cs_ppzksnark_verifier_process_vk_gadget::generate_r1cs_constraints() +{ + compute_vk_alphaB_g1_precomp->generate_r1cs_constraints(); + compute_vk_gamma_beta_g1_precomp->generate_r1cs_constraints(); + + compute_vk_alphaA_g2_precomp->generate_r1cs_constraints(); + compute_vk_alphaC_g2_precomp->generate_r1cs_constraints(); + compute_vk_gamma_beta_g2_precomp->generate_r1cs_constraints(); + compute_vk_gamma_g2_precomp->generate_r1cs_constraints(); + compute_vk_rC_Z_g2_precomp->generate_r1cs_constraints(); +} + +template +void r1cs_ppzksnark_verifier_process_vk_gadget::generate_r1cs_witness() +{ + compute_vk_alphaB_g1_precomp->generate_r1cs_witness(); + compute_vk_gamma_beta_g1_precomp->generate_r1cs_witness(); + + compute_vk_alphaA_g2_precomp->generate_r1cs_witness(); + compute_vk_alphaC_g2_precomp->generate_r1cs_witness(); + compute_vk_gamma_beta_g2_precomp->generate_r1cs_witness(); + compute_vk_gamma_g2_precomp->generate_r1cs_witness(); + compute_vk_rC_Z_g2_precomp->generate_r1cs_witness(); +} + +template +r1cs_ppzksnark_online_verifier_gadget::r1cs_ppzksnark_online_verifier_gadget(protoboard &pb, + const r1cs_ppzksnark_preprocessed_r1cs_ppzksnark_verification_key_variable &pvk, + const pb_variable_array &input, + const size_t elt_size, + const r1cs_ppzksnark_proof_variable &proof, + const pb_variable &result, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix), + pvk(pvk), + input(input), + elt_size(elt_size), + proof(proof), + result(result), + input_len(input.size()) +{ + // accumulate input and store base in acc + acc.reset(new G1_variable(pb, FMT(annotation_prefix, " acc"))); + std::vector > IC_terms; + for (size_t i = 0; i < pvk.encoded_IC_query.size(); ++i) + { + IC_terms.emplace_back(*(pvk.encoded_IC_query[i])); + } + accumulate_input.reset(new G1_multiscalar_mul_gadget(pb, *(pvk.encoded_IC_base), input, elt_size, IC_terms, *acc, FMT(annotation_prefix, " accumulate_input"))); + + // allocate results for precomputation + proof_g_A_h_precomp.reset(new G1_precomputation()); + proof_g_A_g_acc_C_precomp.reset(new G1_precomputation()); + proof_g_A_g_acc_precomp.reset(new G1_precomputation()); + proof_g_A_g_precomp.reset(new G1_precomputation()); + proof_g_B_h_precomp.reset(new G1_precomputation()); + proof_g_C_h_precomp.reset(new G1_precomputation()); + proof_g_C_g_precomp.reset(new G1_precomputation()); + proof_g_K_precomp.reset(new G1_precomputation()); + proof_g_H_precomp.reset(new G1_precomputation()); + + proof_g_B_g_precomp.reset(new G2_precomputation()); + + // do the necessary precomputations + // compute things not available in plain from proof/vk + proof_g_A_g_acc.reset(new G1_variable(pb, FMT(annotation_prefix, " proof_g_A_g_acc"))); + compute_proof_g_A_g_acc.reset(new G1_add_gadget(pb, *(proof.g_A_g), *acc , *proof_g_A_g_acc, FMT(annotation_prefix, " compute_proof_g_A_g_acc"))); + proof_g_A_g_acc_C.reset(new G1_variable(pb, FMT(annotation_prefix, " proof_g_A_g_acc_C"))); + compute_proof_g_A_g_acc_C.reset(new G1_add_gadget(pb, *proof_g_A_g_acc, *(proof.g_C_g) , *proof_g_A_g_acc_C, FMT(annotation_prefix, " compute_proof_g_A_g_acc_C"))); + + compute_proof_g_A_g_acc_precomp.reset(new precompute_G1_gadget(pb, *proof_g_A_g_acc, *proof_g_A_g_acc_precomp, FMT(annotation_prefix, " compute_proof_g_A_g_acc_precomp"))); + compute_proof_g_A_g_acc_C_precomp.reset(new precompute_G1_gadget(pb, *proof_g_A_g_acc_C, *proof_g_A_g_acc_C_precomp, FMT(annotation_prefix, " compute_proof_g_A_g_acc_C_precomp"))); + + // do other precomputations + compute_proof_g_A_h_precomp.reset(new precompute_G1_gadget(pb, *(proof.g_A_h), *proof_g_A_h_precomp, FMT(annotation_prefix, " compute_proof_g_A_h_precomp"))); + compute_proof_g_A_g_precomp.reset(new precompute_G1_gadget(pb, *(proof.g_A_g), *proof_g_A_g_precomp, FMT(annotation_prefix, " compute_proof_g_A_g_precomp"))); + compute_proof_g_B_h_precomp.reset(new precompute_G1_gadget(pb, *(proof.g_B_h), *proof_g_B_h_precomp, FMT(annotation_prefix, " compute_proof_g_B_h_precomp"))); + compute_proof_g_C_h_precomp.reset(new precompute_G1_gadget(pb, *(proof.g_C_h), *proof_g_C_h_precomp, FMT(annotation_prefix, " compute_proof_g_C_h_precomp"))); + compute_proof_g_C_g_precomp.reset(new precompute_G1_gadget(pb, *(proof.g_C_g), *proof_g_C_g_precomp, FMT(annotation_prefix, " compute_proof_g_C_g_precomp"))); + compute_proof_g_H_precomp.reset(new precompute_G1_gadget(pb, *(proof.g_H), *proof_g_H_precomp, FMT(annotation_prefix, " compute_proof_g_H_precomp"))); + compute_proof_g_K_precomp.reset(new precompute_G1_gadget(pb, *(proof.g_K), *proof_g_K_precomp, FMT(annotation_prefix, " compute_proof_g_K_precomp"))); + compute_proof_g_B_g_precomp.reset(new precompute_G2_gadget(pb, *(proof.g_B_g), *proof_g_B_g_precomp, FMT(annotation_prefix, " compute_proof_g_B_g_precomp"))); + + // check validity of A knowledge commitment + kc_A_valid.allocate(pb, FMT(annotation_prefix, " kc_A_valid")); + check_kc_A_valid.reset(new check_e_equals_e_gadget(pb, *proof_g_A_g_precomp, *(pvk.vk_alphaA_g2_precomp), *proof_g_A_h_precomp, *(pvk.pp_G2_one_precomp), kc_A_valid, FMT(annotation_prefix, " check_kc_A_valid"))); + + // check validity of B knowledge commitment + kc_B_valid.allocate(pb, FMT(annotation_prefix, " kc_B_valid")); + check_kc_B_valid.reset(new check_e_equals_e_gadget(pb, *(pvk.vk_alphaB_g1_precomp), *proof_g_B_g_precomp, *proof_g_B_h_precomp, *(pvk.pp_G2_one_precomp), kc_B_valid, FMT(annotation_prefix, " check_kc_B_valid"))); + + // check validity of C knowledge commitment + kc_C_valid.allocate(pb, FMT(annotation_prefix, " kc_C_valid")); + check_kc_C_valid.reset(new check_e_equals_e_gadget(pb, *proof_g_C_g_precomp, *(pvk.vk_alphaC_g2_precomp), *proof_g_C_h_precomp, *(pvk.pp_G2_one_precomp), kc_C_valid, FMT(annotation_prefix, " check_kc_C_valid"))); + + // check QAP divisibility + QAP_valid.allocate(pb, FMT(annotation_prefix, " QAP_valid")); + check_QAP_valid.reset(new check_e_equals_ee_gadget(pb, *proof_g_A_g_acc_precomp, *proof_g_B_g_precomp, *proof_g_H_precomp, *(pvk.vk_rC_Z_g2_precomp), *proof_g_C_g_precomp, *(pvk.pp_G2_one_precomp), QAP_valid, FMT(annotation_prefix, " check_QAP_valid"))); + + // check coefficients + CC_valid.allocate(pb, FMT(annotation_prefix, " CC_valid")); + check_CC_valid.reset(new check_e_equals_ee_gadget(pb, *proof_g_K_precomp, *(pvk.vk_gamma_g2_precomp), *proof_g_A_g_acc_C_precomp, *(pvk.vk_gamma_beta_g2_precomp), *(pvk.vk_gamma_beta_g1_precomp), *proof_g_B_g_precomp, CC_valid, FMT(annotation_prefix, " check_CC_valid"))); + + // final constraint + all_test_results.emplace_back(kc_A_valid); + all_test_results.emplace_back(kc_B_valid); + all_test_results.emplace_back(kc_C_valid); + all_test_results.emplace_back(QAP_valid); + all_test_results.emplace_back(CC_valid); + + all_tests_pass.reset(new conjunction_gadget(pb, all_test_results, result, FMT(annotation_prefix, " all_tests_pass"))); +} + +template +void r1cs_ppzksnark_online_verifier_gadget::generate_r1cs_constraints() +{ + PROFILE_CONSTRAINTS(this->pb, "accumulate verifier input") + { + print_indent(); printf("* Number of bits as an input to verifier gadget: %zu\n", input.size()); + accumulate_input->generate_r1cs_constraints(); + } + + PROFILE_CONSTRAINTS(this->pb, "rest of the verifier") + { + compute_proof_g_A_g_acc->generate_r1cs_constraints(); + compute_proof_g_A_g_acc_C->generate_r1cs_constraints(); + + compute_proof_g_A_g_acc_precomp->generate_r1cs_constraints(); + compute_proof_g_A_g_acc_C_precomp->generate_r1cs_constraints(); + + compute_proof_g_A_h_precomp->generate_r1cs_constraints(); + compute_proof_g_A_g_precomp->generate_r1cs_constraints(); + compute_proof_g_B_h_precomp->generate_r1cs_constraints(); + compute_proof_g_C_h_precomp->generate_r1cs_constraints(); + compute_proof_g_C_g_precomp->generate_r1cs_constraints(); + compute_proof_g_H_precomp->generate_r1cs_constraints(); + compute_proof_g_K_precomp->generate_r1cs_constraints(); + compute_proof_g_B_g_precomp->generate_r1cs_constraints(); + + check_kc_A_valid->generate_r1cs_constraints(); + check_kc_B_valid->generate_r1cs_constraints(); + check_kc_C_valid->generate_r1cs_constraints(); + check_QAP_valid->generate_r1cs_constraints(); + check_CC_valid->generate_r1cs_constraints(); + + all_tests_pass->generate_r1cs_constraints(); + } +} + +template +void r1cs_ppzksnark_online_verifier_gadget::generate_r1cs_witness() +{ + accumulate_input->generate_r1cs_witness(); + + compute_proof_g_A_g_acc->generate_r1cs_witness(); + compute_proof_g_A_g_acc_C->generate_r1cs_witness(); + + compute_proof_g_A_g_acc_precomp->generate_r1cs_witness(); + compute_proof_g_A_g_acc_C_precomp->generate_r1cs_witness(); + + compute_proof_g_A_h_precomp->generate_r1cs_witness(); + compute_proof_g_A_g_precomp->generate_r1cs_witness(); + compute_proof_g_B_h_precomp->generate_r1cs_witness(); + compute_proof_g_C_h_precomp->generate_r1cs_witness(); + compute_proof_g_C_g_precomp->generate_r1cs_witness(); + compute_proof_g_H_precomp->generate_r1cs_witness(); + compute_proof_g_K_precomp->generate_r1cs_witness(); + compute_proof_g_B_g_precomp->generate_r1cs_witness(); + + check_kc_A_valid->generate_r1cs_witness(); + check_kc_B_valid->generate_r1cs_witness(); + check_kc_C_valid->generate_r1cs_witness(); + check_QAP_valid->generate_r1cs_witness(); + check_CC_valid->generate_r1cs_witness(); + + all_tests_pass->generate_r1cs_witness(); +} + +template +r1cs_ppzksnark_verifier_gadget::r1cs_ppzksnark_verifier_gadget(protoboard &pb, + const r1cs_ppzksnark_verification_key_variable &vk, + const pb_variable_array &input, + const size_t elt_size, + const r1cs_ppzksnark_proof_variable &proof, + const pb_variable &result, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix) +{ + pvk.reset(new r1cs_ppzksnark_preprocessed_r1cs_ppzksnark_verification_key_variable()); + compute_pvk.reset(new r1cs_ppzksnark_verifier_process_vk_gadget(pb, vk, *pvk, FMT(annotation_prefix, " compute_pvk"))); + online_verifier.reset(new r1cs_ppzksnark_online_verifier_gadget(pb, *pvk, input, elt_size, proof, result, FMT(annotation_prefix, " online_verifier"))); +} + +template +void r1cs_ppzksnark_verifier_gadget::generate_r1cs_constraints() +{ + PROFILE_CONSTRAINTS(this->pb, "precompute pvk") + { + compute_pvk->generate_r1cs_constraints(); + } + + PROFILE_CONSTRAINTS(this->pb, "online verifier") + { + online_verifier->generate_r1cs_constraints(); + } +} + +template +void r1cs_ppzksnark_verifier_gadget::generate_r1cs_witness() +{ + compute_pvk->generate_r1cs_witness(); + online_verifier->generate_r1cs_witness(); +} + +} // libsnark + +#endif // R1CS_PPZKSNARK_VERIFIER_GADGET_TCC_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/verifiers/tests/test_r1cs_ppzksnark_verifier_gadget.cpp b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/verifiers/tests/test_r1cs_ppzksnark_verifier_gadget.cpp new file mode 100644 index 0000000..299720c --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/gadgets/verifiers/tests/test_r1cs_ppzksnark_verifier_gadget.cpp @@ -0,0 +1,429 @@ +/** + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ +#include "algebra/curves/mnt/mnt4/mnt4_pp.hpp" +#include "algebra/curves/mnt/mnt6/mnt6_pp.hpp" +#include "algebra/fields/field_utils.hpp" +#include "gadgetlib1/gadgets/fields/fp2_gadgets.hpp" +#include "gadgetlib1/gadgets/fields/fp3_gadgets.hpp" +#include "gadgetlib1/gadgets/fields/fp4_gadgets.hpp" +#include "gadgetlib1/gadgets/fields/fp6_gadgets.hpp" +#include "gadgetlib1/gadgets/verifiers/r1cs_ppzksnark_verifier_gadget.hpp" +#include "relations/constraint_satisfaction_problems/r1cs/examples/r1cs_examples.hpp" +#include "zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.hpp" + +using namespace libsnark; + +template +void dump_constraints(const protoboard &pb) +{ +#ifdef DEBUG + for (auto s : pb.constraint_system.constraint_annotations) + { + printf("constraint: %s\n", s.second.c_str()); + } +#endif +} + +template +void test_verifier(const std::string &annotation_A, const std::string &annotation_B) +{ + typedef Fr FieldT_A; + typedef Fr FieldT_B; + + const size_t num_constraints = 50; + const size_t primary_input_size = 3; + + r1cs_example example = generate_r1cs_example_with_field_input(num_constraints, primary_input_size); + assert(example.primary_input.size() == primary_input_size); + + assert(example.constraint_system.is_satisfied(example.primary_input, example.auxiliary_input)); + const r1cs_ppzksnark_keypair keypair = r1cs_ppzksnark_generator(example.constraint_system); + const r1cs_ppzksnark_proof pi = r1cs_ppzksnark_prover(keypair.pk, example.primary_input, example.auxiliary_input); + bool bit = r1cs_ppzksnark_verifier_strong_IC(keypair.vk, example.primary_input, pi); + assert(bit); + + const size_t elt_size = FieldT_A::size_in_bits(); + const size_t primary_input_size_in_bits = elt_size * primary_input_size; + const size_t vk_size_in_bits = r1cs_ppzksnark_verification_key_variable::size_in_bits(primary_input_size); + + protoboard pb; + pb_variable_array vk_bits; + vk_bits.allocate(pb, vk_size_in_bits, "vk_bits"); + + pb_variable_array primary_input_bits; + primary_input_bits.allocate(pb, primary_input_size_in_bits, "primary_input_bits"); + + r1cs_ppzksnark_proof_variable proof(pb, "proof"); + + r1cs_ppzksnark_verification_key_variable vk(pb, vk_bits, primary_input_size, "vk"); + + pb_variable result; + result.allocate(pb, "result"); + + r1cs_ppzksnark_verifier_gadget verifier(pb, vk, primary_input_bits, elt_size, proof, result, "verifier"); + + PROFILE_CONSTRAINTS(pb, "check that proofs lies on the curve") + { + proof.generate_r1cs_constraints(); + } + verifier.generate_r1cs_constraints(); + + bit_vector input_as_bits; + for (const FieldT_A &el : example.primary_input) + { + bit_vector v = convert_field_element_to_bit_vector(el, elt_size); + input_as_bits.insert(input_as_bits.end(), v.begin(), v.end()); + } + + primary_input_bits.fill_with_bits(pb, input_as_bits); + + vk.generate_r1cs_witness(keypair.vk); + proof.generate_r1cs_witness(pi); + verifier.generate_r1cs_witness(); + pb.val(result) = FieldT_B::one(); + + printf("positive test:\n"); + assert(pb.is_satisfied()); + + pb.val(primary_input_bits[0]) = FieldT_B::one() - pb.val(primary_input_bits[0]); + verifier.generate_r1cs_witness(); + pb.val(result) = FieldT_B::one(); + + printf("negative test:\n"); + assert(!pb.is_satisfied()); + PRINT_CONSTRAINT_PROFILING(); + printf("number of constraints for verifier: %zu (verifier is implemented in %s constraints and verifies %s proofs))\n", + pb.num_constraints(), annotation_B.c_str(), annotation_A.c_str()); +} + +template +void test_hardcoded_verifier(const std::string &annotation_A, const std::string &annotation_B) +{ + typedef Fr FieldT_A; + typedef Fr FieldT_B; + + const size_t num_constraints = 50; + const size_t primary_input_size = 3; + + r1cs_example example = generate_r1cs_example_with_field_input(num_constraints, primary_input_size); + assert(example.primary_input.size() == primary_input_size); + + assert(example.constraint_system.is_satisfied(example.primary_input, example.auxiliary_input)); + const r1cs_ppzksnark_keypair keypair = r1cs_ppzksnark_generator(example.constraint_system); + const r1cs_ppzksnark_proof pi = r1cs_ppzksnark_prover(keypair.pk, example.primary_input, example.auxiliary_input); + bool bit = r1cs_ppzksnark_verifier_strong_IC(keypair.vk, example.primary_input, pi); + assert(bit); + + const size_t elt_size = FieldT_A::size_in_bits(); + const size_t primary_input_size_in_bits = elt_size * primary_input_size; + + protoboard pb; + r1cs_ppzksnark_preprocessed_r1cs_ppzksnark_verification_key_variable hardcoded_vk(pb, keypair.vk, "hardcoded_vk"); + pb_variable_array primary_input_bits; + primary_input_bits.allocate(pb, primary_input_size_in_bits, "primary_input_bits"); + + r1cs_ppzksnark_proof_variable proof(pb, "proof"); + + pb_variable result; + result.allocate(pb, "result"); + + r1cs_ppzksnark_online_verifier_gadget online_verifier(pb, hardcoded_vk, primary_input_bits, elt_size, proof, result, "online_verifier"); + + PROFILE_CONSTRAINTS(pb, "check that proofs lies on the curve") + { + proof.generate_r1cs_constraints(); + } + online_verifier.generate_r1cs_constraints(); + + bit_vector input_as_bits; + for (const FieldT_A &el : example.primary_input) + { + bit_vector v = convert_field_element_to_bit_vector(el, elt_size); + input_as_bits.insert(input_as_bits.end(), v.begin(), v.end()); + } + + primary_input_bits.fill_with_bits(pb, input_as_bits); + + proof.generate_r1cs_witness(pi); + online_verifier.generate_r1cs_witness(); + pb.val(result) = FieldT_B::one(); + + printf("positive test:\n"); + assert(pb.is_satisfied()); + + pb.val(primary_input_bits[0]) = FieldT_B::one() - pb.val(primary_input_bits[0]); + online_verifier.generate_r1cs_witness(); + pb.val(result) = FieldT_B::one(); + + printf("negative test:\n"); + assert(!pb.is_satisfied()); + PRINT_CONSTRAINT_PROFILING(); + printf("number of constraints for verifier: %zu (verifier is implemented in %s constraints and verifies %s proofs))\n", + pb.num_constraints(), annotation_B.c_str(), annotation_A.c_str()); +} + +template class VarT, template class MulT> +void test_mul(const std::string &annotation) +{ + typedef typename FpExtT::my_Fp FieldT; + + protoboard pb; + VarT x(pb, "x"); + VarT y(pb, "y"); + VarT xy(pb, "xy"); + MulT mul(pb, x, y, xy, "mul"); + mul.generate_r1cs_constraints(); + + for (size_t i = 0; i < 10; ++i) + { + const FpExtT x_val = FpExtT::random_element(); + const FpExtT y_val = FpExtT::random_element(); + x.generate_r1cs_witness(x_val); + y.generate_r1cs_witness(y_val); + mul.generate_r1cs_witness(); + const FpExtT res = xy.get_element(); + assert(res == x_val*y_val); + assert(pb.is_satisfied()); + } + printf("number of constraints for %s_mul = %zu\n", annotation.c_str(), pb.num_constraints()); +} + +template class VarT, template class SqrT> +void test_sqr(const std::string &annotation) +{ + typedef typename FpExtT::my_Fp FieldT; + + protoboard pb; + VarT x(pb, "x"); + VarT xsq(pb, "xsq"); + SqrT sqr(pb, x, xsq, "sqr"); + sqr.generate_r1cs_constraints(); + + for (size_t i = 0; i < 10; ++i) + { + const FpExtT x_val = FpExtT::random_element(); + x.generate_r1cs_witness(x_val); + sqr.generate_r1cs_witness(); + const FpExtT res = xsq.get_element(); + assert(res == x_val.squared()); + assert(pb.is_satisfied()); + } + printf("number of constraints for %s_sqr = %zu\n", annotation.c_str(), pb.num_constraints()); +} + +template class VarT, template class CycloSqrT> +void test_cyclotomic_sqr(const std::string &annotation) +{ + typedef Fqk FpExtT; + typedef typename FpExtT::my_Fp FieldT; + + + protoboard pb; + VarT x(pb, "x"); + VarT xsq(pb, "xsq"); + CycloSqrT sqr(pb, x, xsq, "sqr"); + sqr.generate_r1cs_constraints(); + + for (size_t i = 0; i < 10; ++i) + { + FpExtT x_val = FpExtT::random_element(); + x_val = ppT::final_exponentiation(x_val); + + x.generate_r1cs_witness(x_val); + sqr.generate_r1cs_witness(); + const FpExtT res = xsq.get_element(); + assert(res == x_val.squared()); + assert(pb.is_satisfied()); + } + printf("number of constraints for %s_cyclotomic_sqr = %zu\n", annotation.c_str(), pb.num_constraints()); +} + +template class VarT> +void test_Frobenius(const std::string &annotation) +{ + typedef typename FpExtT::my_Fp FieldT; + + for (size_t i = 0; i < 100; ++i) + { + protoboard pb; + VarT x(pb, "x"); + VarT x_frob = x.Frobenius_map(i); + + const FpExtT x_val = FpExtT::random_element(); + x.generate_r1cs_witness(x_val); + x_frob.evaluate(); + const FpExtT res = x_frob.get_element(); + assert(res == x_val.Frobenius_map(i)); + assert(pb.is_satisfied()); + } + + printf("Frobenius map for %s correct\n", annotation.c_str()); +} + +template +void test_full_pairing(const std::string &annotation) +{ + typedef Fr FieldT; + + protoboard pb; + G1 > P_val = Fr >::random_element() * G1 >::one(); + G2 > Q_val = Fr >::random_element() * G2 >::one(); + + G1_variable P(pb, "P"); + G2_variable Q(pb, "Q"); + G1_precomputation prec_P; + G2_precomputation prec_Q; + + precompute_G1_gadget compute_prec_P(pb, P, prec_P, "compute_prec_P"); + precompute_G2_gadget compute_prec_Q(pb, Q, prec_Q, "compute_prec_Q"); + + Fqk_variable miller_result(pb, "miller_result"); + mnt_miller_loop_gadget miller(pb, prec_P, prec_Q, miller_result, "miller"); + pb_variable result_is_one; + result_is_one.allocate(pb, "result_is_one"); + final_exp_gadget finexp(pb, miller_result, result_is_one, "finexp"); + + PROFILE_CONSTRAINTS(pb, "precompute P") + { + compute_prec_P.generate_r1cs_constraints(); + } + PROFILE_CONSTRAINTS(pb, "precompute Q") + { + compute_prec_Q.generate_r1cs_constraints(); + } + PROFILE_CONSTRAINTS(pb, "Miller loop") + { + miller.generate_r1cs_constraints(); + } + PROFILE_CONSTRAINTS(pb, "final exp") + { + finexp.generate_r1cs_constraints(); + } + PRINT_CONSTRAINT_PROFILING(); + + P.generate_r1cs_witness(P_val); + compute_prec_P.generate_r1cs_witness(); + Q.generate_r1cs_witness(Q_val); + compute_prec_Q.generate_r1cs_witness(); + miller.generate_r1cs_witness(); + finexp.generate_r1cs_witness(); + assert(pb.is_satisfied()); + + affine_ate_G1_precomp > native_prec_P = other_curve::affine_ate_precompute_G1(P_val); + affine_ate_G2_precomp > native_prec_Q = other_curve::affine_ate_precompute_G2(Q_val); + Fqk > native_miller_result = other_curve::affine_ate_miller_loop(native_prec_P, native_prec_Q); + + Fqk > native_finexp_result = other_curve::final_exponentiation(native_miller_result); + printf("Must match:\n"); + finexp.result->get_element().print(); + native_finexp_result.print(); + + assert(finexp.result->get_element() == native_finexp_result); + + printf("number of constraints for full pairing (Fr is %s) = %zu\n", annotation.c_str(), pb.num_constraints()); +} + +template +void test_full_precomputed_pairing(const std::string &annotation) +{ + typedef Fr FieldT; + + protoboard pb; + G1 > P_val = Fr >::random_element() * G1 >::one(); + G2 > Q_val = Fr >::random_element() * G2 >::one(); + + G1_precomputation prec_P(pb, P_val, "prec_P"); + G2_precomputation prec_Q(pb, Q_val, "prec_Q"); + + Fqk_variable miller_result(pb, "miller_result"); + mnt_miller_loop_gadget miller(pb, prec_P, prec_Q, miller_result, "miller"); + pb_variable result_is_one; + result_is_one.allocate(pb, "result_is_one"); + final_exp_gadget finexp(pb, miller_result, result_is_one, "finexp"); + + PROFILE_CONSTRAINTS(pb, "Miller loop") + { + miller.generate_r1cs_constraints(); + } + PROFILE_CONSTRAINTS(pb, "final exp") + { + finexp.generate_r1cs_constraints(); + } + PRINT_CONSTRAINT_PROFILING(); + + miller.generate_r1cs_witness(); + finexp.generate_r1cs_witness(); + assert(pb.is_satisfied()); + + affine_ate_G1_precomp > native_prec_P = other_curve::affine_ate_precompute_G1(P_val); + affine_ate_G2_precomp > native_prec_Q = other_curve::affine_ate_precompute_G2(Q_val); + Fqk > native_miller_result = other_curve::affine_ate_miller_loop(native_prec_P, native_prec_Q); + + Fqk > native_finexp_result = other_curve::final_exponentiation(native_miller_result); + printf("Must match:\n"); + finexp.result->get_element().print(); + native_finexp_result.print(); + + assert(finexp.result->get_element() == native_finexp_result); + + printf("number of constraints for full precomputed pairing (Fr is %s) = %zu\n", annotation.c_str(), pb.num_constraints()); +} + +int main(void) +{ + start_profiling(); + mnt4_pp::init_public_params(); + mnt6_pp::init_public_params(); + + test_mul("mnt4_Fp2"); + test_sqr("mnt4_Fp2"); + + test_mul("mnt4_Fp4"); + test_sqr("mnt4_Fp4"); + test_cyclotomic_sqr("mnt4_Fp4"); + test_exponentiation_gadget(mnt4_final_exponent_last_chunk_abs_of_w0, "mnt4_Fq4"); + test_Frobenius("mnt4_Fq4"); + + test_mul("mnt6_Fp3"); + test_sqr("mnt6_Fp3"); + + test_mul("mnt6_Fp6"); + test_sqr("mnt6_Fp6"); + test_cyclotomic_sqr("mnt6_Fp6"); + test_exponentiation_gadget(mnt6_final_exponent_last_chunk_abs_of_w0, "mnt6_Fq6"); + test_Frobenius("mnt6_Fq6"); + + test_G2_checker_gadget("mnt4"); + test_G2_checker_gadget("mnt6"); + + test_G1_variable_precomp("mnt4"); + test_G1_variable_precomp("mnt6"); + + test_G2_variable_precomp("mnt4"); + test_G2_variable_precomp("mnt6"); + + test_mnt_miller_loop("mnt4"); + test_mnt_miller_loop("mnt6"); + + test_mnt_e_over_e_miller_loop("mnt4"); + test_mnt_e_over_e_miller_loop("mnt6"); + + test_mnt_e_times_e_over_e_miller_loop("mnt4"); + test_mnt_e_times_e_over_e_miller_loop("mnt6"); + + test_full_pairing("mnt4"); + test_full_pairing("mnt6"); + + test_full_precomputed_pairing("mnt4"); + test_full_precomputed_pairing("mnt6"); + + test_verifier("mnt4", "mnt6"); + test_verifier("mnt6", "mnt4"); + + test_hardcoded_verifier("mnt4", "mnt6"); + test_hardcoded_verifier("mnt6", "mnt4"); +} diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/pb_variable.hpp b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/pb_variable.hpp new file mode 100644 index 0000000..fdf64d0 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/pb_variable.hpp @@ -0,0 +1,144 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef PB_VARIABLE_HPP_ +#define PB_VARIABLE_HPP_ + +#include +#include +#include +#include "common/utils.hpp" +#include "relations/variable.hpp" + +namespace libsnark { + +typedef size_t lc_index_t; + +template +class protoboard; + +template +class pb_variable : public variable { +public: + pb_variable(const var_index_t index = 0) : variable(index) {}; + + void allocate(protoboard &pb, const std::string &annotation=""); +}; + +template +class pb_variable_array : private std::vector > +{ + typedef std::vector > contents; +public: + using typename contents::iterator; + using typename contents::const_iterator; + using typename contents::reverse_iterator; + using typename contents::const_reverse_iterator; + + using contents::begin; + using contents::end; + using contents::rbegin; + using contents::rend; + using contents::emplace_back; + using contents::insert; + using contents::reserve; + using contents::size; + using contents::empty; + using contents::operator[]; + using contents::resize; + + pb_variable_array() : contents() {}; + pb_variable_array(size_t count, const pb_variable &value) : contents(count, value) {}; + pb_variable_array(typename contents::const_iterator first, typename contents::const_iterator last) : contents(first, last) {}; + pb_variable_array(typename contents::const_reverse_iterator first, typename contents::const_reverse_iterator last) : contents(first, last) {}; + void allocate(protoboard &pb, const size_t n, const std::string &annotation_prefix=""); + + void fill_with_field_elements(protoboard &pb, const std::vector& vals) const; + void fill_with_bits(protoboard &pb, const bit_vector& bits) const; + void fill_with_bits_of_ulong(protoboard &pb, const unsigned long i) const; + void fill_with_bits_of_field_element(protoboard &pb, const FieldT &r) const; + + std::vector get_vals(const protoboard &pb) const; + bit_vector get_bits(const protoboard &pb) const; + + FieldT get_field_element_from_bits(const protoboard &pb) const; +}; + +/* index 0 corresponds to the constant term (used in legacy code) */ +#define ONE pb_variable(0) + +template +class pb_linear_combination : public linear_combination { +public: + bool is_variable; + lc_index_t index; + + pb_linear_combination(); + pb_linear_combination(const pb_variable &var); + + void assign(protoboard &pb, const linear_combination &lc); + void evaluate(protoboard &pb) const; + + bool is_constant() const; + FieldT constant_term() const; +}; + +template +class pb_linear_combination_array : private std::vector > +{ + typedef std::vector > contents; +public: + using typename contents::iterator; + using typename contents::const_iterator; + using typename contents::reverse_iterator; + using typename contents::const_reverse_iterator; + + using contents::begin; + using contents::end; + using contents::rbegin; + using contents::rend; + using contents::emplace_back; + using contents::insert; + using contents::reserve; + using contents::size; + using contents::empty; + using contents::operator[]; + using contents::resize; + + pb_linear_combination_array() : contents() {}; + pb_linear_combination_array(const pb_variable_array &arr) { for (auto &v : arr) this->emplace_back(pb_linear_combination(v)); }; + pb_linear_combination_array(size_t count) : contents(count) {}; + pb_linear_combination_array(size_t count, const pb_linear_combination &value) : contents(count, value) {}; + pb_linear_combination_array(typename contents::const_iterator first, typename contents::const_iterator last) : contents(first, last) {}; + pb_linear_combination_array(typename contents::const_reverse_iterator first, typename contents::const_reverse_iterator last) : contents(first, last) {}; + + void evaluate(protoboard &pb) const; + + void fill_with_field_elements(protoboard &pb, const std::vector& vals) const; + void fill_with_bits(protoboard &pb, const bit_vector& bits) const; + void fill_with_bits_of_ulong(protoboard &pb, const unsigned long i) const; + void fill_with_bits_of_field_element(protoboard &pb, const FieldT &r) const; + + std::vector get_vals(const protoboard &pb) const; + bit_vector get_bits(const protoboard &pb) const; + + FieldT get_field_element_from_bits(const protoboard &pb) const; +}; + +template +linear_combination pb_sum(const pb_linear_combination_array &v); + +template +linear_combination pb_packing_sum(const pb_linear_combination_array &v); + +template +linear_combination pb_coeff_sum(const pb_linear_combination_array &v, const std::vector &coeffs); + +} // libsnark +#include "gadgetlib1/pb_variable.tcc" + +#endif // PB_VARIABLE_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/pb_variable.tcc b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/pb_variable.tcc new file mode 100644 index 0000000..7e90f25 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/pb_variable.tcc @@ -0,0 +1,329 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef PB_VARIABLE_TCC_ +#define PB_VARIABLE_TCC_ +#include +#include "gadgetlib1/protoboard.hpp" +#include "common/utils.hpp" + +namespace libsnark { + +template +void pb_variable::allocate(protoboard &pb, const std::string &annotation) +{ + this->index = pb.allocate_var_index(annotation); +} + +/* allocates pb_variable array in MSB->LSB order */ +template +void pb_variable_array::allocate(protoboard &pb, const size_t n, const std::string &annotation_prefix) +{ +#ifdef DEBUG + assert(annotation_prefix != ""); +#endif + (*this).resize(n); + + for (size_t i = 0; i < n; ++i) + { + (*this)[i].allocate(pb, FMT(annotation_prefix, "_%zu", i)); + } +} + +template +void pb_variable_array::fill_with_field_elements(protoboard &pb, const std::vector& vals) const +{ + assert(this->size() == vals.size()); + for (size_t i = 0; i < vals.size(); ++i) + { + pb.val((*this)[i]) = vals[i]; + } +} + +template +void pb_variable_array::fill_with_bits(protoboard &pb, const bit_vector& bits) const +{ + assert(this->size() == bits.size()); + for (size_t i = 0; i < bits.size(); ++i) + { + pb.val((*this)[i]) = (bits[i] ? FieldT::one() : FieldT::zero()); + } +} + +template +void pb_variable_array::fill_with_bits_of_field_element(protoboard &pb, const FieldT &r) const +{ + const bigint rint = r.as_bigint(); + for (size_t i = 0; i < this->size(); ++i) + { + pb.val((*this)[i]) = rint.test_bit(i) ? FieldT::one() : FieldT::zero(); + } +} + +template +void pb_variable_array::fill_with_bits_of_ulong(protoboard &pb, const unsigned long i) const +{ + this->fill_with_bits_of_field_element(pb, FieldT(i, true)); +} + +template +std::vector pb_variable_array::get_vals(const protoboard &pb) const +{ + std::vector result(this->size()); + for (size_t i = 0; i < this->size(); ++i) + { + result[i] = pb.val((*this)[i]); + } + return result; +} + +template +bit_vector pb_variable_array::get_bits(const protoboard &pb) const +{ + bit_vector result; + for (size_t i = 0; i < this->size(); ++i) + { + const FieldT v = pb.val((*this)[i]); + assert(v == FieldT::zero() || v == FieldT::one()); + result.push_back(v == FieldT::one()); + } + return result; +} + +template +FieldT pb_variable_array::get_field_element_from_bits(const protoboard &pb) const +{ + FieldT result = FieldT::zero(); + + for (size_t i = 0; i < this->size(); ++i) + { + /* push in the new bit */ + const FieldT v = pb.val((*this)[this->size()-1-i]); + assert(v == FieldT::zero() || v == FieldT::one()); + result += result + v; + } + + return result; +} + +template +pb_linear_combination::pb_linear_combination() +{ + this->is_variable = false; +} + +template +pb_linear_combination::pb_linear_combination(const pb_variable &var) +{ + this->is_variable = true; + this->index = var.index; + this->terms.emplace_back(linear_term(var)); +} + +template +void pb_linear_combination::assign(protoboard &pb, const linear_combination &lc) +{ + assert(this->is_variable == false); + this->index = pb.allocate_lc_index(); + this->terms = lc.terms; +} + +template +void pb_linear_combination::evaluate(protoboard &pb) const +{ + if (this->is_variable) + { + return; // do nothing + } + + FieldT sum = 0; + for (auto term : this->terms) + { + sum += term.coeff * pb.val(pb_variable(term.index)); + } + + pb.lc_val(*this) = sum; +} + +template +bool pb_linear_combination::is_constant() const +{ + if (is_variable) + { + return (index == 0); + } + else + { + for (auto term : this->terms) + { + if (term.index != 0) + { + return false; + } + } + + return true; + } +} + +template +FieldT pb_linear_combination::constant_term() const +{ + if (is_variable) + { + return (index == 0 ? FieldT::one() : FieldT::zero()); + } + else + { + FieldT result = FieldT::zero(); + for (auto term : this->terms) + { + if (term.index == 0) + { + result += term.coeff; + } + } + return result; + } +} + +template +void pb_linear_combination_array::evaluate(protoboard &pb) const +{ + for (size_t i = 0; i < this->size(); ++i) + { + (*this)[i].evaluate(pb); + } +} + +template +void pb_linear_combination_array::fill_with_field_elements(protoboard &pb, const std::vector& vals) const +{ + assert(this->size() == vals.size()); + for (size_t i = 0; i < vals.size(); ++i) + { + pb.lc_val((*this)[i]) = vals[i]; + } +} + +template +void pb_linear_combination_array::fill_with_bits(protoboard &pb, const bit_vector& bits) const +{ + assert(this->size() == bits.size()); + for (size_t i = 0; i < bits.size(); ++i) + { + pb.lc_val((*this)[i]) = (bits[i] ? FieldT::one() : FieldT::zero()); + } +} + +template +void pb_linear_combination_array::fill_with_bits_of_field_element(protoboard &pb, const FieldT &r) const +{ + const bigint rint = r.as_bigint(); + for (size_t i = 0; i < this->size(); ++i) + { + pb.lc_val((*this)[i]) = rint.test_bit(i) ? FieldT::one() : FieldT::zero(); + } +} + +template +void pb_linear_combination_array::fill_with_bits_of_ulong(protoboard &pb, const unsigned long i) const +{ + this->fill_with_bits_of_field_element(pb, FieldT(i)); +} + +template +std::vector pb_linear_combination_array::get_vals(const protoboard &pb) const +{ + std::vector result(this->size()); + for (size_t i = 0; i < this->size(); ++i) + { + result[i] = pb.lc_val((*this)[i]); + } + return result; +} + +template +bit_vector pb_linear_combination_array::get_bits(const protoboard &pb) const +{ + bit_vector result; + for (size_t i = 0; i < this->size(); ++i) + { + const FieldT v = pb.lc_val((*this)[i]); + assert(v == FieldT::zero() || v == FieldT::one()); + result.push_back(v == FieldT::one()); + } + return result; +} + +template +FieldT pb_linear_combination_array::get_field_element_from_bits(const protoboard &pb) const +{ + FieldT result = FieldT::zero(); + + for (size_t i = 0; i < this->size(); ++i) + { + /* push in the new bit */ + const FieldT v = pb.lc_val((*this)[this->size()-1-i]); + assert(v == FieldT::zero() || v == FieldT::one()); + result += result + v; + } + + return result; +} + +template +linear_combination pb_sum(const pb_linear_combination_array &v) +{ + linear_combination result; + for (auto &term : v) + { + result = result + term; + } + + return result; +} + +template +linear_combination pb_packing_sum(const pb_linear_combination_array &v) +{ + FieldT twoi = FieldT::one(); // will hold 2^i entering each iteration + std::vector > all_terms; + for (auto &lc : v) + { + for (auto &term : lc.terms) + { + all_terms.emplace_back(twoi * term); + } + twoi += twoi; + } + + return linear_combination(all_terms); +} + +template +linear_combination pb_coeff_sum(const pb_linear_combination_array &v, const std::vector &coeffs) +{ + assert(v.size() == coeffs.size()); + std::vector > all_terms; + + auto coeff_it = coeffs.begin(); + for (auto &lc : v) + { + for (auto &term : lc.terms) + { + all_terms.emplace_back((*coeff_it) * term); + } + ++coeff_it; + } + + return linear_combination(all_terms); +} + + +} // libsnark +#endif // PB_VARIABLE_TCC diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/protoboard.hpp b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/protoboard.hpp new file mode 100644 index 0000000..8ef4a53 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/protoboard.hpp @@ -0,0 +1,75 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef PROTOBOARD_HPP_ +#define PROTOBOARD_HPP_ + +#include +#include +#include +#include +#include +#include "gadgetlib1/pb_variable.hpp" +#include "relations/constraint_satisfaction_problems/r1cs/r1cs.hpp" +#include "common/utils.hpp" + +namespace libsnark { + +template +class r1cs_constraint; + +template +class r1cs_constraint_system; + +template +class protoboard { +private: + FieldT constant_term; /* only here, because pb.val() needs to be able to return reference to the constant 1 term */ + r1cs_variable_assignment values; /* values[0] will hold the value of the first allocated variable of the protoboard, *NOT* constant 1 */ + var_index_t next_free_var; + lc_index_t next_free_lc; + std::vector lc_values; + +public: + r1cs_constraint_system constraint_system; + protoboard(); + + void clear_values(); + + FieldT& val(const pb_variable &var); + FieldT val(const pb_variable &var) const; + + FieldT& lc_val(const pb_linear_combination &lc); + FieldT lc_val(const pb_linear_combination &lc) const; + + void add_r1cs_constraint(const r1cs_constraint &constr, const std::string &annotation=""); + void augment_variable_annotation(const pb_variable &v, const std::string &postfix); + bool is_satisfied() const; + void dump_variables() const; + + size_t num_constraints() const; + size_t num_inputs() const; + size_t num_variables() const; + + void set_input_sizes(const size_t primary_input_size); + + r1cs_variable_assignment full_variable_assignment() const; + r1cs_primary_input primary_input() const; + r1cs_auxiliary_input auxiliary_input() const; + r1cs_constraint_system get_constraint_system() const; + + friend class pb_variable; + friend class pb_linear_combination; + +private: + var_index_t allocate_var_index(const std::string &annotation=""); + lc_index_t allocate_lc_index(); +}; + +} // libsnark +#include "gadgetlib1/protoboard.tcc" +#endif // PROTOBOARD_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/protoboard.tcc b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/protoboard.tcc new file mode 100644 index 0000000..882af28 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/protoboard.tcc @@ -0,0 +1,189 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef PROTOBOARD_TCC_ +#define PROTOBOARD_TCC_ + +#include +#include +#include "common/profiling.hpp" + +namespace libsnark { + +template +protoboard::protoboard() +{ + constant_term = FieldT::one(); + +#ifdef DEBUG + constraint_system.variable_annotations[0] = "ONE"; +#endif + + next_free_var = 1; /* to account for constant 1 term */ + next_free_lc = 0; +} + +template +void protoboard::clear_values() +{ + std::fill(values.begin(), values.end(), FieldT::zero()); +} + +template +var_index_t protoboard::allocate_var_index(const std::string &annotation) +{ +#ifdef DEBUG + assert(annotation != ""); + constraint_system.variable_annotations[next_free_var] = annotation; +#else + UNUSED(annotation); +#endif + ++constraint_system.auxiliary_input_size; + values.emplace_back(FieldT::zero()); + return next_free_var++; +} + +template +lc_index_t protoboard::allocate_lc_index() +{ + lc_values.emplace_back(FieldT::zero()); + return next_free_lc++; +} + +template +FieldT& protoboard::val(const pb_variable &var) +{ + assert(var.index <= values.size()); + return (var.index == 0 ? constant_term : values[var.index-1]); +} + +template +FieldT protoboard::val(const pb_variable &var) const +{ + assert(var.index <= values.size()); + return (var.index == 0 ? constant_term : values[var.index-1]); +} + +template +FieldT& protoboard::lc_val(const pb_linear_combination &lc) +{ + if (lc.is_variable) + { + return this->val(pb_variable(lc.index)); + } + else + { + assert(lc.index < lc_values.size()); + return lc_values[lc.index]; + } +} + +template +FieldT protoboard::lc_val(const pb_linear_combination &lc) const +{ + if (lc.is_variable) + { + return this->val(pb_variable(lc.index)); + } + else + { + assert(lc.index < lc_values.size()); + return lc_values[lc.index]; + } +} + +template +void protoboard::add_r1cs_constraint(const r1cs_constraint &constr, const std::string &annotation) +{ +#ifdef DEBUG + assert(annotation != ""); + constraint_system.constraint_annotations[constraint_system.constraints.size()] = annotation; +#else + UNUSED(annotation); +#endif + constraint_system.constraints.emplace_back(constr); +} + +template +void protoboard::augment_variable_annotation(const pb_variable &v, const std::string &postfix) +{ +#ifdef DEBUG + auto it = constraint_system.variable_annotations.find(v.index); + constraint_system.variable_annotations[v.index] = (it == constraint_system.variable_annotations.end() ? "" : it->second + " ") + postfix; +#endif +} + +template +bool protoboard::is_satisfied() const +{ + return constraint_system.is_satisfied(primary_input(), auxiliary_input()); +} + +template +void protoboard::dump_variables() const +{ +#ifdef DEBUG + for (size_t i = 0; i < constraint_system.num_variables; ++i) + { + printf("%-40s --> ", constraint_system.variable_annotations[i].c_str()); + values[i].as_bigint().print_hex(); + } +#endif +} + +template +size_t protoboard::num_constraints() const +{ + return constraint_system.num_constraints(); +} + +template +size_t protoboard::num_inputs() const +{ + return constraint_system.num_inputs(); +} + +template +size_t protoboard::num_variables() const +{ + return next_free_var - 1; +} + +template +void protoboard::set_input_sizes(const size_t primary_input_size) +{ + assert(primary_input_size <= num_variables()); + constraint_system.primary_input_size = primary_input_size; + constraint_system.auxiliary_input_size = num_variables() - primary_input_size; +} + +template +r1cs_variable_assignment protoboard::full_variable_assignment() const +{ + return values; +} + +template +r1cs_primary_input protoboard::primary_input() const +{ + return r1cs_primary_input(values.begin(), values.begin() + num_inputs()); +} + +template +r1cs_auxiliary_input protoboard::auxiliary_input() const +{ + return r1cs_primary_input(values.begin() + num_inputs(), values.end()); +} + +template +r1cs_constraint_system protoboard::get_constraint_system() const +{ + return constraint_system; +} + +} // libsnark +#endif // PROTOBOARD_TCC_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/tests/gadgetlib1_test.cpp b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/tests/gadgetlib1_test.cpp new file mode 100644 index 0000000..4fc5106 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib1/tests/gadgetlib1_test.cpp @@ -0,0 +1,32 @@ +/** @file + ***************************************************************************** + Unit tests for gadgetlib1 - main() for running all tests + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include +#include "gadgetlib1/examples/simple_example.hpp" +#include "zk_proof_systems/ppzksnark/r1cs_ppzksnark/examples/run_r1cs_ppzksnark.hpp" + +namespace { + +TEST(gadgetLib1,Integration) { + typedef libsnark::Fr FieldT; + // Create an example constraint system and translate to libsnark format + libsnark::default_ec_pp::init_public_params(); + const auto example = libsnark::gen_r1cs_example_from_protoboard(100); + const bool test_serialization = false; + // Run ppzksnark. Jump into function for breakdown + const bool bit = libsnark::run_r1cs_ppzksnark(example, test_serialization); + EXPECT_TRUE(bit); +}; + +} + +int main(int argc, char **argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib2/adapters.cpp b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib2/adapters.cpp new file mode 100644 index 0000000..03d4d5d --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib2/adapters.cpp @@ -0,0 +1,94 @@ +/** @file + ***************************************************************************** + Implementation of an adapter for interfacing to SNARKs. + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include "adapters.hpp" + +using gadgetlib2::Variable; +using gadgetlib2::Rank1Constraint; + +namespace gadgetlib2 { + +typedef GadgetLibAdapter GLA; + +GLA::linear_term_t GLA::convert(const LinearTerm& lt) const { + const variable_index_t var = lt.variable_.index_; + const Fp_elem_t coeff = convert(lt.coeff_); + return{ var, coeff }; +} + +GLA::linear_combination_t GLA::convert(const LinearCombination& lc) const { + sparse_vec_t sparse_vec; + sparse_vec.reserve(lc.linearTerms_.size()); + for (auto lt : lc.linearTerms_) { + sparse_vec.emplace_back(convert(lt)); + } + const Fp_elem_t offset = convert(lc.constant_); + return{ sparse_vec, offset }; +} + +GLA::constraint_t GLA::convert(const Constraint& constraint) const { + const auto rank1_constraint = dynamic_cast(constraint); + return constraint_t(convert(rank1_constraint.a()), + convert(rank1_constraint.b()), + convert(rank1_constraint.c())); +} + +GLA::constraint_sys_t GLA::convert(const ConstraintSystem& constraint_sys) const { + constraint_sys_t retval; + retval.reserve(constraint_sys.constraintsPtrs_.size()); + for (auto constraintPtr : constraint_sys.constraintsPtrs_) { + retval.emplace_back(convert(*constraintPtr)); + } + return retval; +} + +GLA::assignment_t GLA::convert(const VariableAssignment& assignment) const { + assignment_t retval; + for (const auto assignmentPair : assignment) { + const variable_index_t var = assignmentPair.first.index_; + const Fp_elem_t elem = convert(assignmentPair.second); + retval[var] = elem; + } + return retval; +} + +void GLA::resetVariableIndex() { // This is a hack, used for testing + Variable::nextFreeIndex_ = 0; +} + +/***TODO: Remove reliance of GadgetLibAdapter conversion on global variable indices, and the resulting limit of single protoboard instance at a time. +This limitation is to prevent a logic bug that may occur if the variables used are given different indices in different generations of the same constraint system. +The indices are assigned on the Variable constructor, using the global variable nextFreeIndex. Thus, creating two protoboards in the same program may cause +unexpected behavior when converting. +Moreover, the bug will create more variables than needed in the converted system, e.g. if variables 0,1,3,4 were used in the gadgetlib2 +generated system, than the conversion will create a new r1cs system with variables 0,1,2,3,4 and assign variable 2 the value zero +(when converting the assignment). +Everything should be fixed soon. +If you are sure you know what you are doing, you can comment out the ASSERT line. +*/ +GLA::protoboard_t GLA::convert(const Protoboard& pb) const { + //GADGETLIB_ASSERT(pb.numVars()==getNextFreeIndex(), "Some Variables were created and not used, or, more than one protoboard was used."); + return protoboard_t(convert(pb.constraintSystem()), convert(pb.assignment())); +} + +GLA::Fp_elem_t GLA::convert(FElem fElem) const { + using gadgetlib2::R1P_Elem; + fElem.promoteToFieldType(gadgetlib2::R1P); // convert fElem from FConst to R1P_Elem + const R1P_Elem* pR1P = dynamic_cast(fElem.elem_.get()); + return pR1P->elem_; +} + +bool operator==(const GLA::linear_combination_t& lhs, + const GLA::linear_term_t& rhs) { + return lhs.first.size() == 1 && + lhs.first.at(0) == rhs && + lhs.second == Fp(0); +} + +} diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib2/adapters.hpp b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib2/adapters.hpp new file mode 100644 index 0000000..ba4678d --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib2/adapters.hpp @@ -0,0 +1,71 @@ +/** @file + ***************************************************************************** + Declaration of an adapter to POD types for interfacing to SNARKs + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef LIBSNARK_GADGETLIB2_INCLUDE_GADGETLIB2_ADAPTERS_HPP_ +#define LIBSNARK_GADGETLIB2_INCLUDE_GADGETLIB2_ADAPTERS_HPP_ + +#include +#include +#include +#include "pp.hpp" +#include "variable.hpp" +#include "constraint.hpp" +#include "protoboard.hpp" + +using gadgetlib2::LinearTerm; +using gadgetlib2::LinearCombination; +using gadgetlib2::Constraint; +using gadgetlib2::ConstraintSystem; +using gadgetlib2::VariableAssignment; +using gadgetlib2::Protoboard; +using gadgetlib2::FElem; + + +namespace gadgetlib2 { + +/** + * This class is a temporary hack for quick integration of Fp constraints with ppsnark. It is the + * IDDQD of classes and has "god mode" friend access to many of the gadgetlib classes. This will + * be refactored out in the future. --Shaul + */ +class GadgetLibAdapter { +public: + typedef unsigned long variable_index_t; + typedef gadgetlib2::Fp Fp_elem_t; + typedef ::std::pair linear_term_t; + typedef ::std::vector sparse_vec_t; + typedef ::std::pair linear_combination_t; + typedef ::std::tuple constraint_t; + typedef ::std::vector constraint_sys_t; + typedef ::std::map assignment_t; + typedef ::std::pair protoboard_t; + + GadgetLibAdapter() {}; + + linear_term_t convert(const LinearTerm& lt) const; + linear_combination_t convert(const LinearCombination& lc) const; + constraint_t convert(const Constraint& constraint) const; + constraint_sys_t convert(const ConstraintSystem& constraint_sys) const; + assignment_t convert(const VariableAssignment& assignment) const; + static void resetVariableIndex(); ///< Resets variable index to 0 to make variable indices deterministic. + //TODO: Kill GadgetLibAdapter::resetVariableIndex() + static size_t getNextFreeIndex(){return Variable::nextFreeIndex_;} + protoboard_t convert(const Protoboard& pb) const; + Fp_elem_t convert(FElem fElem) const; + static size_t getVariableIndex(const Variable& v){return v.index_;} +}; + +bool operator==(const GadgetLibAdapter::linear_combination_t& lhs, + const GadgetLibAdapter::linear_term_t& rhs); + +} + +#endif // LIBSNARK_GADGETLIB2_INCLUDE_GADGETLIB2_ADAPTERS_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib2/constraint.cpp b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib2/constraint.cpp new file mode 100644 index 0000000..2033e25 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib2/constraint.cpp @@ -0,0 +1,216 @@ +/** @file + ***************************************************************************** + Implementation of the Constraint class. + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include +#include +#include +#include +#include +#include "constraint.hpp" +#include "variable.hpp" + +using ::std::string; +using ::std::vector; +using ::std::set; +using ::std::cout; +using ::std::cerr; +using ::std::endl; +using ::std::shared_ptr; + +namespace gadgetlib2 { + +/*************************************************************************************************/ +/*************************************************************************************************/ +/******************* ******************/ +/******************* class Constraint ******************/ +/******************* ******************/ +/*************************************************************************************************/ +/*************************************************************************************************/ + +#ifdef DEBUG +Constraint::Constraint(const string& name) : name_(name) {} +#else +Constraint::Constraint(const string& name) { UNUSED(name); } +#endif + +string Constraint::name() const { +# ifdef DEBUG + return name_; +# else + return ""; +# endif +} + +/***********************************/ +/*** END OF CLASS DEFINITION ***/ +/***********************************/ + +/*************************************************************************************************/ +/*************************************************************************************************/ +/******************* ******************/ +/******************* class Rank1Constraint ******************/ +/******************* ******************/ +/*************************************************************************************************/ +/*************************************************************************************************/ + +Rank1Constraint::Rank1Constraint(const LinearCombination &a, + const LinearCombination &b, + const LinearCombination &c, + const string& name) + : Constraint(name), a_(a), b_(b), c_(c) {} + +LinearCombination Rank1Constraint::a() const {return a_;} +LinearCombination Rank1Constraint::b() const {return b_;} +LinearCombination Rank1Constraint::c() const {return c_;} + +bool Rank1Constraint::isSatisfied(const VariableAssignment& assignment, + const PrintOptions& printOnFail) const { + const FElem ares = a_.eval(assignment); + const FElem bres = b_.eval(assignment); + const FElem cres = c_.eval(assignment); + if (ares*bres != cres) { +# ifdef DEBUG + if (printOnFail == PrintOptions::DBG_PRINT_IF_NOT_SATISFIED) { + cerr << GADGETLIB2_FMT("Constraint named \"%s\" not satisfied. Constraint is:", + name().c_str()) << endl; + cerr << annotation() << endl; + cerr << "Variable assignments are:" << endl; + const Variable::set varSet = getUsedVariables(); + for(const Variable& var : varSet) { + cerr << var.name() << ": " << assignment.at(var).asString() << endl; + } + cerr << "a: " << ares.asString() << endl; + cerr << "b: " << bres.asString() << endl; + cerr << "a*b: " << (ares*bres).asString() << endl; + cerr << "c: " << cres.asString() << endl; + } +# else + UNUSED(printOnFail); +# endif + return false; + } + return true; +} + +string Rank1Constraint::annotation() const { +# ifndef DEBUG + return ""; +# endif + return string("( ") + a_.asString() + " ) * ( " + b_.asString() + " ) = "+ c_.asString(); +} + +const Variable::set Rank1Constraint::getUsedVariables() const { + Variable::set retSet; + const Variable::set aSet = a_.getUsedVariables(); + retSet.insert(aSet.begin(), aSet.end()); + const Variable::set bSet = b_.getUsedVariables(); + retSet.insert(bSet.begin(), bSet.end()); + const Variable::set cSet = c_.getUsedVariables(); + retSet.insert(cSet.begin(), cSet.end()); + return retSet; +} + +/***********************************/ +/*** END OF CLASS DEFINITION ***/ +/***********************************/ + +/*************************************************************************************************/ +/*************************************************************************************************/ +/******************* ******************/ +/******************* class PolynomialConstraint ******************/ +/******************* ******************/ +/*************************************************************************************************/ +/*************************************************************************************************/ + +PolynomialConstraint::PolynomialConstraint(const Polynomial& a, const Polynomial& b, + const string& name) : Constraint(name), a_(a), b_(b) {} + +bool PolynomialConstraint::isSatisfied(const VariableAssignment& assignment, + const PrintOptions& printOnFail) const { + const FElem aEval = a_.eval(assignment); + const FElem bEval = b_.eval(assignment); + if (aEval != bEval) { +# ifdef DEBUG + if(printOnFail == PrintOptions::DBG_PRINT_IF_NOT_SATISFIED) { + cerr << GADGETLIB2_FMT("Constraint named \"%s\" not satisfied. Constraint is:", + name().c_str()) << endl; + cerr << annotation() << endl; + cerr << "Expecting: " << aEval << " == " << bEval << endl; + cerr << "Variable assignments are:" << endl; + const Variable::set varSet = getUsedVariables(); + for(const Variable& var : varSet) { + cerr << var.name() << ": " << assignment.at(var).asString() << endl; + } + } +# else + UNUSED(printOnFail); +# endif + + return false; + } + return true; +} + +string PolynomialConstraint::annotation() const { +# ifndef DEBUG + return ""; +# endif + return a_.asString() + " == " + b_.asString(); +} + +const Variable::set PolynomialConstraint::getUsedVariables() const { + Variable::set retSet; + const Variable::set aSet = a_.getUsedVariables(); + retSet.insert(aSet.begin(), aSet.end()); + const Variable::set bSet = b_.getUsedVariables(); + retSet.insert(bSet.begin(), bSet.end()); + return retSet; +} + +/***********************************/ +/*** END OF CLASS DEFINITION ***/ +/***********************************/ + + +void ConstraintSystem::addConstraint(const Rank1Constraint& c) { + constraintsPtrs_.emplace_back(::std::shared_ptr(new Rank1Constraint(c))); +} + +void ConstraintSystem::addConstraint(const PolynomialConstraint& c) { + constraintsPtrs_.emplace_back(::std::shared_ptr(new PolynomialConstraint(c))); +} + +bool ConstraintSystem::isSatisfied(const VariableAssignment& assignment, + const PrintOptions& printOnFail) const { + for(size_t i = 0; i < constraintsPtrs_.size(); ++i) { + if (!constraintsPtrs_[i]->isSatisfied(assignment, printOnFail)){ + return false; + } + } + return true; +} + +string ConstraintSystem::annotation() const { + string retVal("\n"); + for(auto i = constraintsPtrs_.begin(); i != constraintsPtrs_.end(); ++i) { + retVal += (*i)->annotation() + '\n'; + } + return retVal; +} + +Variable::set ConstraintSystem::getUsedVariables() const { + Variable::set retSet; + for(auto& pConstraint : constraintsPtrs_) { + const Variable::set curSet = pConstraint->getUsedVariables(); + retSet.insert(curSet.begin(), curSet.end()); + } + return retSet; +} + +} // namespace gadgetlib2 diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib2/constraint.hpp b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib2/constraint.hpp new file mode 100644 index 0000000..5b51e44 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib2/constraint.hpp @@ -0,0 +1,177 @@ +/** @file + ***************************************************************************** + Declaration of the Constraint class. + + A constraint is an algebraic equation which can be either satisfied by an assignment, + (the equation is true with that assignment) or unsatisfied. For instance the rank-1 + constraint (X * Y = 15) is satisfied by {X=5 Y=3} or {X=3 Y=5} + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef LIBSNARK_GADGETLIB2_INCLUDE_GADGETLIB2_CONSTRAINT_HPP_ +#define LIBSNARK_GADGETLIB2_INCLUDE_GADGETLIB2_CONSTRAINT_HPP_ + +#include +#include +#include "variable.hpp" + +namespace gadgetlib2 { + +enum class PrintOptions { + DBG_PRINT_IF_NOT_SATISFIED, + DBG_PRINT_IF_TRUE, + DBG_PRINT_IF_FALSE, + NO_DBG_PRINT +}; + +/*************************************************************************************************/ +/*************************************************************************************************/ +/******************* ******************/ +/******************* class Constraint ******************/ +/******************* ******************/ +/*************************************************************************************************/ +/*************************************************************************************************/ + +/// An abstract class for a field agnostic constraint. The derived classes will be field specific. +class Constraint { +public: + explicit Constraint(const ::std::string& name); // casting disallowed by 'explicit' + ::std::string name() const; ///< @returns name of the constraint as a string + /** + @param[in] assignment - An assignment of field elements for each variable. + @param[in] printOnFail - when set to true, an unsatisfied constraint will print to stderr + information explaining why it is not satisfied. + @returns true if constraint is satisfied by the assignment + **/ + virtual bool isSatisfied(const VariableAssignment& assignment, + const PrintOptions& printOnFail) const = 0; + /// @returns the constraint in a human readable string format + virtual ::std::string annotation() const = 0; + virtual const Variable::set getUsedVariables() const = 0; + virtual Polynomial asPolynomial() const = 0; +protected: +# ifdef DEBUG + ::std::string name_; +# endif + +}; // class Constraint + +/***********************************/ +/*** END OF CLASS DEFINITION ***/ +/***********************************/ + +/*************************************************************************************************/ +/*************************************************************************************************/ +/******************* ******************/ +/******************* class Rank1Constraint ******************/ +/******************* ******************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +/// A rank-1 prime characteristic constraint. The constraint is defined by * = +/// where x is an assignment of field elements to the variables. +class Rank1Constraint : public Constraint { +private: + LinearCombination a_, b_, c_; // * = +public: + Rank1Constraint(const LinearCombination& a, + const LinearCombination& b, + const LinearCombination& c, + const ::std::string& name); + + LinearCombination a() const; + LinearCombination b() const; + LinearCombination c() const; + + virtual bool isSatisfied(const VariableAssignment& assignment, + const PrintOptions& printOnFail = PrintOptions::NO_DBG_PRINT) const; + virtual ::std::string annotation() const; + virtual const Variable::set getUsedVariables() const; /**< @returns a list of all variables + used in the constraint */ + virtual Polynomial asPolynomial() const {return a_ * b_ - c_;} +}; // class Rank1Constraint + +/***********************************/ +/*** END OF CLASS DEFINITION ***/ +/***********************************/ + +/*************************************************************************************************/ +/*************************************************************************************************/ +/******************* ******************/ +/******************* class PolynomialConstraint ******************/ +/******************* ******************/ +/*************************************************************************************************/ +/*************************************************************************************************/ + +class PolynomialConstraint : public Constraint { +private: + Polynomial a_, b_; +public: + PolynomialConstraint(const Polynomial& a, + const Polynomial& b, + const ::std::string& name); + + bool isSatisfied(const VariableAssignment& assignment, + const PrintOptions& printOnFail = PrintOptions::NO_DBG_PRINT) const; + ::std::string annotation() const; + virtual const Variable::set getUsedVariables() const; /**< @returns a list of all variables + used in the constraint */ + virtual Polynomial asPolynomial() const {return a_ - b_;} +}; // class PolynomialConstraint + +/***********************************/ +/*** END OF CLASS DEFINITION ***/ +/***********************************/ + +/*************************************************************************************************/ +/*************************************************************************************************/ +/******************* ******************/ +/******************* class ConstraintSystem ******************/ +/******************* ******************/ +/*************************************************************************************************/ +/*************************************************************************************************/ + +class ConstraintSystem { +protected: + typedef ::std::shared_ptr ConstraintPtr; + ::std::vector constraintsPtrs_; +public: + ConstraintSystem() : constraintsPtrs_() {}; + + /** + Checks if all constraints are satisfied by an assignment. + @param[in] assignment - An assignment of field elements for each variable. + @param[in] printOnFail - when set to true, an unsatisfied constraint will print to stderr + information explaining why it is not satisfied. + @returns true if constraint is satisfied by the assignment + **/ + bool isSatisfied(const VariableAssignment& assignment, + const PrintOptions& printOnFail = PrintOptions::NO_DBG_PRINT) const; + void addConstraint(const Rank1Constraint& c); + void addConstraint(const PolynomialConstraint& c); + ::std::string annotation() const; + Variable::set getUsedVariables() const; + + typedef ::std::set< ::std::unique_ptr > PolyPtrSet; + /// Required for interfacing with BREX. Should be optimized in the future + PolyPtrSet getConstraintPolynomials() const { + PolyPtrSet retset; + for(const auto& pConstraint : constraintsPtrs_) { + retset.insert(::std::unique_ptr(new Polynomial(pConstraint->asPolynomial()))); + } + return retset; + } + size_t getNumberOfConstraints() { return constraintsPtrs_.size(); } + ConstraintPtr getConstraint(size_t idx){ return constraintsPtrs_[idx];} + friend class GadgetLibAdapter; +}; // class ConstraintSystem + +/***********************************/ +/*** END OF CLASS DEFINITION ***/ +/***********************************/ + +} // namespace gadgetlib2 + +#endif // LIBSNARK_GADGETLIB2_INCLUDE_GADGETLIB2_CONSTRAINT_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib2/examples/simple_example.cpp b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib2/examples/simple_example.cpp new file mode 100644 index 0000000..3bbe321 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib2/examples/simple_example.cpp @@ -0,0 +1,57 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include "gadgetlib2/examples/simple_example.hpp" + +#include "gadgetlib2/adapters.hpp" +#include "gadgetlib2/gadget.hpp" +#include "gadgetlib2/integration.hpp" + +namespace libsnark { + +/* NOTE: all examples here actually generate one constraint less to account for soundness constraint in QAP */ +r1cs_example > gen_r1cs_example_from_gadgetlib2_protoboard(const size_t size) +{ + typedef Fr FieldT; + + gadgetlib2::initPublicParamsFromDefaultPp(); + // necessary in case a protoboard was built before, libsnark assumes variable indices always + // begin with 0 so we must reset the index before creating constraints which will be used by + // libsnark + gadgetlib2::GadgetLibAdapter::resetVariableIndex(); + + // create a gadgetlib2 gadget. This part is done by both generator and prover. + auto pb = gadgetlib2::Protoboard::create(gadgetlib2::R1P); + gadgetlib2::VariableArray A(size, "A"); + gadgetlib2::VariableArray B(size, "B"); + gadgetlib2::Variable result("result"); + auto g = gadgetlib2::InnerProduct_Gadget::create(pb, A, B, result); + // create constraints. This part is done by generator. + g->generateConstraints(); + // create assignment (witness). This part is done by prover. + for (size_t k = 0; k < size; ++k) + { + pb->val(A[k]) = std::rand() % 2; + pb->val(B[k]) = std::rand() % 2; + } + g->generateWitness(); + // translate constraint system to libsnark format. + r1cs_constraint_system cs = get_constraint_system_from_gadgetlib2(*pb); + // translate full variable assignment to libsnark format + const r1cs_variable_assignment full_assignment = get_variable_assignment_from_gadgetlib2(*pb); + // extract primary and auxiliary input + const r1cs_primary_input primary_input(full_assignment.begin(), full_assignment.begin() + cs.num_inputs()); + const r1cs_auxiliary_input auxiliary_input(full_assignment.begin() + cs.num_inputs(), full_assignment.end()); + + assert(cs.is_valid()); + assert(cs.is_satisfied(primary_input, auxiliary_input)); + + return r1cs_example(cs, primary_input, auxiliary_input); +} + +} // libsnark + diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib2/examples/simple_example.hpp b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib2/examples/simple_example.hpp new file mode 100644 index 0000000..4440146 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib2/examples/simple_example.hpp @@ -0,0 +1,20 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef SIMPLE_EXAMPLE_HPP_ +#define SIMPLE_EXAMPLE_HPP_ + +#include "common/default_types/ec_pp.hpp" +#include "relations/constraint_satisfaction_problems/r1cs/examples/r1cs_examples.hpp" + +namespace libsnark { + +r1cs_example > gen_r1cs_example_from_gadgetlib2_protoboard(const size_t size); + +} // libsnark + +#endif // SIMPLE_EXAMPLE_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib2/examples/tutorial.cpp b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib2/examples/tutorial.cpp new file mode 100644 index 0000000..01f7543 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib2/examples/tutorial.cpp @@ -0,0 +1,505 @@ +/** @file +******************************************************************************** +Tutorial and usage examples of the gadgetlib2 library and ppzkSNARK integration. +This file is meant to be read top-down as a tutorial for gadget writing. + ***************************************************************************** + Tutorial and usage examples of the gadgetlib2 library. + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include +#include +#include "relations/constraint_satisfaction_problems/r1cs/examples/r1cs_examples.hpp" +#include "gadgetlib2/examples/simple_example.hpp" +#include "zk_proof_systems/ppzksnark/r1cs_ppzksnark/examples/run_r1cs_ppzksnark.hpp" + +namespace gadgetExamples { + +using namespace gadgetlib2; + +/* + This test gives the first example of a construction of a constraint system. We use the terms + 'Constraint System' and 'Circuit' interchangeably rather loosly. It is easy to + visualize a circuit with inputs and outputs. Each gate imposes some logic on the inputs and + output wires. For instance, AND(inp1, inp2) will impose the 'constraint' (inp1 & inp2 = out) + Thus, we can also think of this circuit as a system of constraints. Each gate is a mathematical + constraint and each wire is a variable. In the AND example over a boolean field {0,1} we would + write the constraint as (inp1 * inp2 == out). This constraint is 'satisfied' relative to an + assignment if we assign values to {inp1, inp2, out} such that the constraint evaluates to TRUE. + All following examples will be either field agnostic or of a specific form of prime fields: + (1) Field agnostic case: In these examples we create high level circuits by using lower level + circuits. This way we can ignore the specifics of a field and assume the lower level takes + care of this. If we must explicitly write constraints in these circuits, they will always + be very basic constraints which are defined over every field (e.g. x + y = 0). + (2) All field specific examples in this library are for a prime characteristic field with the + special form of 'quadratic rank 1 polynomials', or R1P. This is the only form used with the + current implementaition of SNARKs. The form for these constraints is + (Linear Combination) * (Linear Combination) == (Linear Combination). + The library has been designed to allow future addition of other characteristics/forms in + the future by implementing only low level circuits for these forms. +*/ +TEST(Examples, ProtoboardUsage) { + // Initialize prime field parameters. This is always needed for R1P. + initPublicParamsFromDefaultPp(); + // The protoboard is the 'memory manager' which holds all constraints (when creating the + // verifying circuit) and variable assignments (when creating the proof witness). We specify + // the type as R1P, this can be augmented in the future to allow for BOOLEAN or GF2_EXTENSION + // fields in the future. + ProtoboardPtr pb = Protoboard::create(R1P); + // We now create 3 input variables and one output + VariableArray input(3, "input"); + Variable output("output"); + // We can now add some constraints. The string is for debuging purposes and can be a textual + // description of the constraint + pb->addRank1Constraint(input[0], 5 + input[2], output, + "Constraint 1: input[0] * (5 + input[2]) == output"); + // The second form addUnaryConstraint(LinearCombination) means (LinearCombination == 0). + pb->addUnaryConstraint(input[1] - output, + "Constraint 2: input[1] - output == 0"); + // Notice this could also have been written: + // pb->addRank1Constraint(1, input[1] - input[2], 0, ""); + // + // For fields with more general forms, once implemented, we could use + // addGeneralConstraint(Polynomial1, Polynomial2, string) which translates to the constraint + // (Polynomial1 == Polynomial2). Example: + // pb->addGeneralConstraint(input[0] * (3 + input[1]) * input[2], output + 5, + // "input[0] * (3 + input[1]) * input[2] == output + 5"); + // + // Now we can assign values to the variables and see if the constraints are satisfied. + // Later, when we will run a SNARK (or any other proof system), the constraints will be + // used by the verifier, and the assigned values will be used by the prover. + // Notice the protoboard stores the assignment values. + pb->val(input[0]) = pb->val(input[1]) = pb->val(input[2]) = pb->val(output) = 42; + EXPECT_FALSE(pb->isSatisfied()); + // The constraint system is not satisfied. Now lets try values which satisfy the two equations + // above: + pb->val(input[0]) = 1; + pb->val(input[1]) = pb->val(output) = 42; // input[1] - output == 0 + pb->val(input[2]) = 37; // 1 * (5 + 37) == 42 + EXPECT_TRUE(pb->isSatisfied()); +} + +/* + In the above example we explicitly wrote all constraints and assignments. + + In this example we will construct a very simple gadget, one that implements a NAND gate. This + gadget is field-agnostic as it only uses lower level gadgets and the field elments '0' and '1'. + + Gadgets are the framework which allow us to delegate construction of sophisticated circuitry + to lower levels. Each gadget can construct a constraint system or a witness or both, by + defining constraints and assignments as well as by utilizing sub-gadgets. +*/ + +class NAND_Gadget : public Gadget { +public: + // This is a convention we use to always create gadgets as if from a factory class. This will + // be needed later for gadgets which have different implementaions in different fields. + static GadgetPtr create(ProtoboardPtr pb, + const FlagVariableArray& inputs, + const FlagVariable& output); + // generateConstraints() is the method which creates all constraints on the protoboard + void generateConstraints(); + // generateWitness() is the method which generates the witness by assigning a valid value to + // each wire in the circuit (variable) and putting this on the protoboard + void generateWitness(); +private: + // constructor is private in order to stick to the convention that gadgets are created using a + // create() method. This may not make sense now, but when dealing with non-field agnostic + // gadgets it is very convenient to have a factory class with this convention. + // Notice the protoboard. This can be thought of as a 'memory manager' which holds the circuit + // as the constraints are being built, and the 'wire values' as the witness is being built + NAND_Gadget(ProtoboardPtr pb, const FlagVariableArray& inputs, const FlagVariable& output); + // init() does any non trivial work which we don't want in the constructor. This is where we + // will 'wire' the sub-gadgets into the circuit. Each sub-gadget can be thought of as a + // circuit gate with some specific functionality. + void init(); + // we want every gadget to be explicitly constructed + DISALLOW_COPY_AND_ASSIGN(NAND_Gadget); + + // This is an internal gadget. Once a gadget is created it can be used as a black box gate. We + // will initialize this pointer to be an AND_Gadget in the init() method. + GadgetPtr andGadget_; + // These are internal variables used by the class. They will always include the variables from + // the constructor, but can include many more as well. Notice that almost always the variables + // can be declared 'const', as these are local copies of formal variables, and do not change + // over the span of the class' lifetime. + const VariableArray inputs_; + const FlagVariable output_; + const FlagVariable andResult_; +}; + +// IMPLEMENTATION +// Most constructors are trivial and only initialize and assert values. +NAND_Gadget::NAND_Gadget(ProtoboardPtr pb, + const FlagVariableArray& inputs, + const FlagVariable& output) + : Gadget(pb), inputs_(inputs), output_(output), andResult_("andResult") {} + +void NAND_Gadget::init() { + // we 'wire' the AND gate. + andGadget_ = AND_Gadget::create(pb_, inputs_, andResult_); +} + +// The create() method will usually look like this, for field-agnostic gadgets: +GadgetPtr NAND_Gadget::create(ProtoboardPtr pb, + const FlagVariableArray& inputs, + const FlagVariable& output) { + GadgetPtr pGadget(new NAND_Gadget(pb, inputs, output)); + pGadget->init(); + return pGadget; +} + +void NAND_Gadget::generateConstraints() { + // we will invoke the AND gate constraint generator + andGadget_->generateConstraints(); + // and add our out negation constraint in order to make this a NAND gate + addRank1Constraint(1, 1 - andResult_, output_, "1 * (1 - andResult) = output"); + // Another way to write the same constraint is: + // addUnaryConstraint(1 - andResult_ - output_, "1 - andResult == output"); + // + // At first look, it would seem that this is enough. However, the AND_Gadget expects all of its + // inputs to be boolean, a dishonest prover could put non-boolean inputs, so we must check this + // here. Notice 'FlagVariable' means a variable which we intend to hold only '0' or '1', but + // this is just a convention (it is a typedef for Variable) and we must enforce it. + // Look into the internals of the R1P implementation of AND_Gadget and see that + // {2, 1, 0} as inputs with {1} as output would satisfy all constraints, even though this is + // clearly not our intent! + for (const auto& input : inputs_) { + enforceBooleanity(input); // This adds a constraint of the form: input * (1 - input) == 0 + } +} + +void NAND_Gadget::generateWitness() { + // First we can assert that all input values are indeed boolean. The purpose of this assertion + // is simply to print a clear error message, it is not security critical. + // Notice the method val() which returns a reference to the current assignment for a variable + for (const auto& input : inputs_) { + GADGETLIB_ASSERT(val(input) == 0 || val(input) == 1, "NAND input is not boolean"); + } + // we will invoke the AND gate witness generator, this will set andResult_ correctly + andGadget_->generateWitness(); + // and now we set the value of output_ + val(output_) = 1 - val(andResult_); + // notice the use of 'val()' to tell the protoboard to assign this new value to the + // variable 'output_'. The variable itself is only a formal variable and never changes. +} + +// And now for a test which will exemplify the usage: +TEST(Examples, NAND_Gadget) { + // initialize the field + initPublicParamsFromDefaultPp(); + // create a protoboard for a system of rank 1 constraints over a prime field. + ProtoboardPtr pb = Protoboard::create(R1P); + // create 5 variables inputs[0]...iputs[4]. The string "inputs" is used for debug messages + FlagVariableArray inputs(5, "inputs"); + FlagVariable output("output"); + GadgetPtr nandGadget = NAND_Gadget::create(pb, inputs, output); + // now we can generate a constraint system (or circuit) + nandGadget->generateConstraints(); + // if we try to evaluate the circuit now, an exception will be thrown, because we will + // be attempting to evaluate unasigned variables. + EXPECT_ANY_THROW(pb->isSatisfied()); + // so lets assign the input variables for NAND and try again after creating the witness + for (const auto& input : inputs) { + pb->val(input) = 1; + } + nandGadget->generateWitness(); + EXPECT_TRUE(pb->isSatisfied()); + EXPECT_TRUE(pb->val(output) == 0); + // now lets try to ruin something and see what happens + pb->val(inputs[2]) = 0; + EXPECT_FALSE(pb->isSatisfied()); + // now let try to cheat. If we hadn't enforced booleanity, this would have worked! + pb->val(inputs[1]) = 2; + EXPECT_FALSE(pb->isSatisfied()); + // now lets reset inputs[1] to a valid value + pb->val(inputs[1]) = 1; + // before, we set both the inputs and the output. Notice the output is still set to '0' + EXPECT_TRUE(pb->val(output) == 0); + // Now we will let the gadget compute the result using generateWitness() and see what happens + nandGadget->generateWitness(); + EXPECT_TRUE(pb->val(output) == 1); + EXPECT_TRUE(pb->isSatisfied()); +} + +/* + Another example showing the use of DualVariable. A DualVariable is a variable which holds both + a bitwise representation of a word and a packed representation (e.g. both the packed value {42} + and the unpacked value {1,0,1,0,1,0}). If the word is short enough + (for example any integer smaller than the prime characteristic) then the packed representation + will be stored in 1 field element. 'word' in this context means a set of bits, it is a + convention which means we expect some semantic ability to decompose the packed value into its + bits. + The use of DualVariables is for efficiency reasons. More on this at the end of this example. + In this example we will construct a gadget which receives as input a packed integer value + called 'hash', and a 'difficulty' level in bits, and constructs a circuit validating that the + first 'difficulty' bits of 'hash' are '0'. For simplicity we will assume 'hash' is always 64 + bits long. +*/ + +class HashDifficultyEnforcer_Gadget : public Gadget { +public: + static GadgetPtr create(ProtoboardPtr pb, + const MultiPackedWord& hashValue, + const size_t difficultyBits); + void generateConstraints(); + void generateWitness(); +private: + const size_t hashSizeInBits_; + const size_t difficultyBits_; + DualWord hashValue_; + // This GadgetPtr will be a gadget to unpack hashValue_ from packed representation to bit + // representation. Recall 'DualWord' holds both values, but only the packed version will be + // recieved as input to the constructor. + GadgetPtr hashValueUnpacker_; + + HashDifficultyEnforcer_Gadget(ProtoboardPtr pb, + const MultiPackedWord& hashValue, + const size_t difficultyBits); + void init(); + DISALLOW_COPY_AND_ASSIGN(HashDifficultyEnforcer_Gadget); +}; + +// IMPLEMENTATION +HashDifficultyEnforcer_Gadget::HashDifficultyEnforcer_Gadget(ProtoboardPtr pb, + const MultiPackedWord& hashValue, + const size_t difficultyBits) + : Gadget(pb), hashSizeInBits_(64), difficultyBits_(difficultyBits), + hashValue_(hashValue, UnpackedWord(64, "hashValue_u")) +{ +} + +void HashDifficultyEnforcer_Gadget::init() { + // because we are using a prime field with large characteristic, we can assume a 64 bit value + // fits in the first element of a multipacked variable. + GADGETLIB_ASSERT(hashValue_.multipacked().size() == 1, "multipacked word size too large"); + // A DualWord_Gadget's constraints assert that the unpacked and packed values represent the + // same integer element. The generateWitnes() method has two modes, one for packing (taking the + // bit representation as input) and one for unpacking (creating the bit representation from + // the packed representation) + hashValueUnpacker_ = DualWord_Gadget::create(pb_, hashValue_, PackingMode::UNPACK); +} + +GadgetPtr HashDifficultyEnforcer_Gadget::create(ProtoboardPtr pb, + const MultiPackedWord& hashValue, + const size_t difficultyBits) { + GadgetPtr pGadget(new HashDifficultyEnforcer_Gadget(pb, hashValue, difficultyBits)); + pGadget->init(); + return pGadget; +} + +void HashDifficultyEnforcer_Gadget::generateConstraints() { + // enforce that both representations are equal + hashValueUnpacker_->generateConstraints(); + // add constraints asserting that the first 'difficultyBits' bits of 'hashValue' equal 0. Note + // endianness, unpacked()[0] is LSB and unpacked()[63] is MSB + for (size_t i = 0; i < difficultyBits_; ++i) { + addUnaryConstraint(hashValue_.unpacked()[63 - i], GADGETLIB2_FMT("hashValue[%u] == 0", 63 - i)); + } +} + +void HashDifficultyEnforcer_Gadget::generateWitness() { + // Take the packed representation and unpack to bits. + hashValueUnpacker_->generateWitness(); + // In a real setting we would add an assertion that the value will indeed satisfy the + // difficulty constraint, and notify the user with an error otherwise. As this is a tutorial, + // we'll let invalid values pass through so that we can see how isSatisfied() returns false. +} + +// Remember we pointed out that DualVariables are used for efficiency reasons. Now is the time to +// elaborate on this. As you've seen, we needed a bit representation in order to check the first +// bits of hashValue. But hashValue may be used in many other places, for instance we may want to +// check equality with another value. Checking equality on a packed representation will 'cost' us +// 1 constraint, while checking equality on the unpacked value will 'cost' us 64 constraints. This +// translates heavily into proof construction time and memory in the ppzkSNARK proof system. + +TEST(Examples, HashDifficultyEnforcer_Gadget) { + initPublicParamsFromDefaultPp(); + auto pb = Protoboard::create(R1P); + const MultiPackedWord hashValue(64, R1P, "hashValue"); + const size_t difficulty = 10; + auto difficultyEnforcer = HashDifficultyEnforcer_Gadget::create(pb, hashValue, difficulty); + difficultyEnforcer->generateConstraints(); + // constraints are created but no assignment yet. Will throw error on evaluation + EXPECT_ANY_THROW(pb->isSatisfied()); + pb->val(hashValue[0]) = 42; + difficultyEnforcer->generateWitness(); + // First 10 bits of 42 (when represented as a 64 bit number) are '0' so this should work + EXPECT_TRUE(pb->isSatisfied(PrintOptions::DBG_PRINT_IF_NOT_SATISFIED)); + pb->val(hashValue[0]) = 1000000000000000000; + // This is a value > 2^54 so we expect constraint system not to be satisfied. + difficultyEnforcer->generateWitness(); // This would have failed had we put an assertion + EXPECT_FALSE(pb->isSatisfied()); +} + + +/* + In this exampe we will construct a gadget which builds a circuit for proof (witness) and + validation (constraints) that a bitcoin transaction's sum of inputs equals the the sum of + outputs + miners fee. Construction of the proof will include finding the miners' + fee. This fee can be thought of as an output of the circuit. + + This is a field specific gadget, as we will use the '+' operator freely. The addition + operation works as expected over integers while in prime characteristic fields but not so in + extension fields. If you are not familiar with extension fields, don't worry about it. Simply + be aware that + and * behave differently in different fields and don't necessarily give the + integer values you would expect. + + The library design supports multiple field constructs due to different applied use cases. Some + cryptogragraphic applications may need extension fields while others may need prime fields + but with constraints which are not rank-1 and yet others may need boolean circuits. The library + was designed so that high level gadgets can be reused by implementing only the low level for + a new field or constraint structure. + + Later we will supply a recipe for creation of such field specfic gadgets with agnostic + interfaces. We use a few conventions here in order to ease the process by using macros. +*/ + + +// This is a macro which creates an interface class for all field specific derived gadgets +// Convention is: class {GadgetName}_GadgetBase +CREATE_GADGET_BASE_CLASS(VerifyTransactionAmounts_GadgetBase); + +// Notice the multiple inheritance. We must specify the interface as well as the field specific +// base gadget. This is what allows the factory class to decide at compile time which field +// specific class to instantiate for every protoboard. See design notes in "gadget.hpp" +// Convention is: class {FieldType}_{GadgetName}_Gadget +class R1P_VerifyTransactionAmounts_Gadget : public VerifyTransactionAmounts_GadgetBase, + public R1P_Gadget { +public: + void generateConstraints(); + void generateWitness(); + + // We give the factory class friend access in order to instantiate via private constructor. + friend class VerifyTransactionAmounts_Gadget; +private: + R1P_VerifyTransactionAmounts_Gadget(ProtoboardPtr pb, + const VariableArray& txInputAmounts, + const VariableArray& txOutputAmounts, + const Variable& minersFee); + void init(); + + const VariableArray txInputAmounts_; + const VariableArray txOutputAmounts_; + const Variable minersFee_; + + DISALLOW_COPY_AND_ASSIGN(R1P_VerifyTransactionAmounts_Gadget); +}; + +// create factory class using CREATE_GADGET_FACTORY_CLASS_XX macro (substitute XX with the number +// of arguments to the constructor, excluding the protoboard). Sometimes we want multiple +// constructors, see AND_Gadget for example. In this case we will have to manually write the +// factory class. +CREATE_GADGET_FACTORY_CLASS_3(VerifyTransactionAmounts_Gadget, + VariableArray, txInputAmounts, + VariableArray, txOutputAmounts, + Variable, minersFee); + +// IMPLEMENTATION + +// Destructor for the Base class +VerifyTransactionAmounts_GadgetBase::~VerifyTransactionAmounts_GadgetBase() {} + +void R1P_VerifyTransactionAmounts_Gadget::generateConstraints() { + addUnaryConstraint(sum(txInputAmounts_) - sum(txOutputAmounts_) - minersFee_, + "sum(txInputAmounts) == sum(txOutputAmounts) + minersFee"); + // It would seem this is enough, but an adversary could cause an overflow of one side of the + // equation over the field modulus. In fact, for every input/output sum we will always find a + // miners' fee which will satisfy this constraint! + // It is left as an excercise for the reader to implement additional constraints (and witness) + // to check that each of the amounts (inputs, outputs, fee) are between 0 and 21,000,000 * 1E8 + // satoshis. Combine this with a maximum amount of inputs/outputs to disallow field overflow. + // + // Hint: use Comparison_Gadget to create a gadget which compares a variable's assigned value + // to a constant. Use a vector of these new gadgets to check each amount. + // Don't forget to: + // (1) Wire these gadgets in init() + // (2) Invoke the gadgets' constraints in generateConstraints() + // (3) Invoke the gadgets' witnesses in generateWitness() +} + +void R1P_VerifyTransactionAmounts_Gadget::generateWitness() { + FElem sumInputs = 0; + FElem sumOutputs = 0; + for (const auto& inputAmount : txInputAmounts_) { + sumInputs += val(inputAmount); + } + for (const auto& outputAmount : txOutputAmounts_) { + sumOutputs += val(outputAmount); + } + val(minersFee_) = sumInputs - sumOutputs; +} + +R1P_VerifyTransactionAmounts_Gadget::R1P_VerifyTransactionAmounts_Gadget( + ProtoboardPtr pb, + const VariableArray& txInputAmounts, + const VariableArray& txOutputAmounts, + const Variable& minersFee) + // Notice we must initialize 3 base classes (diamond inheritance): + : Gadget(pb), VerifyTransactionAmounts_GadgetBase(pb), R1P_Gadget(pb), + txInputAmounts_(txInputAmounts), txOutputAmounts_(txOutputAmounts), + minersFee_(minersFee) {} + +void R1P_VerifyTransactionAmounts_Gadget::init() {} + +/* + As promised, recipe for creating field specific gadgets with agnostic interfaces: + + (1) Create the Base class using macro: + CREATE_GADGET_BASE_CLASS({GadgetName}_GadgetBase); + (2) Create the destructor for the base class: + {GadgetName_Gadget}Base::~{GadgetName}_GadgetBase() {} + (3) Create any field specific gadgets with multiple inheritance: + class {FieldType}_{GadgetName}_Gadget : public {GadgetName}_GadgetBase, + public {FieldType_Gadget} + Notice all arguments to the constructors must be const& in order to use the factory class + macro. Constructor arguments must be the same for all field specific implementations. + (4) Give the factory class {GadgetName}_Gadget public friend access to the field specific + classes. + (5) Create the factory class using the macro: + CREATE_GADGET_FACTORY_CLASS_XX({GadgetName}_Gadget, type1, input1, type2, input2, ... , + typeXX, inputXX); +*/ + +TEST(Examples, R1P_VerifyTransactionAmounts_Gadget) { + initPublicParamsFromDefaultPp(); + auto pb = Protoboard::create(R1P); + const VariableArray inputAmounts(2, "inputAmounts"); + const VariableArray outputAmounts(3, "outputAmounts"); + const Variable minersFee("minersFee"); + auto verifyTx = VerifyTransactionAmounts_Gadget::create(pb, inputAmounts, outputAmounts, + minersFee); + verifyTx->generateConstraints(); + pb->val(inputAmounts[0]) = pb->val(inputAmounts[1]) = 2; + pb->val(outputAmounts[0]) = pb->val(outputAmounts[1]) = pb->val(outputAmounts[2]) = 1; + verifyTx->generateWitness(); + EXPECT_TRUE(pb->isSatisfied()); + EXPECT_EQ(pb->val(minersFee), 1); + pb->val(minersFee) = 3; + EXPECT_FALSE(pb->isSatisfied()); +} + +/* + Below is an example of integrating gadgetlib2 constructed constraint systems with the + ppzkSNARK. +*/ + +TEST(gadgetLib2,Integration) { + initPublicParamsFromDefaultPp(); + // Create an example constraint system and translate to libsnark format + const libsnark::r1cs_example > example = libsnark::gen_r1cs_example_from_gadgetlib2_protoboard(100); + const bool test_serialization = false; + // Run ppzksnark. Jump into function for breakdown + const bool bit = libsnark::run_r1cs_ppzksnark(example, test_serialization); + EXPECT_TRUE(bit); +}; + +} // namespace gadgetExamples + +int main(int argc, char **argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib2/gadget.cpp b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib2/gadget.cpp new file mode 100644 index 0000000..71a0409 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib2/gadget.cpp @@ -0,0 +1,955 @@ +/** @file + ***************************************************************************** + Declarations of the interfaces and basic gadgets for R1P (Rank 1 prime characteristic) + constraint systems. + + See details in gadget.hpp . + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include +#include +#include "gadget.hpp" + +using ::std::shared_ptr; +using ::std::string; +using ::std::vector; +using ::std::cout; +using ::std::cerr; +using ::std::endl; + +namespace gadgetlib2 { + +/*************************************************************************************************/ +/*************************************************************************************************/ +/******************* ******************/ +/******************* Gadget Interfaces ******************/ +/******************* ******************/ +/*************************************************************************************************/ +/*************************************************************************************************/ + +/***********************************/ +/*** Gadget ***/ +/***********************************/ + +Gadget::Gadget(ProtoboardPtr pb) : pb_(pb) { + GADGETLIB_ASSERT(pb != NULL, "Attempted to create gadget with uninitialized Protoboard."); +} + +void Gadget::generateWitness() { + GADGETLIB_FATAL("Attempted to generate witness for an incomplete Gadget type."); +} + +void Gadget::addUnaryConstraint(const LinearCombination& a, const ::std::string& name) { + pb_->addUnaryConstraint(a, name); +} + +void Gadget::addRank1Constraint(const LinearCombination& a, + const LinearCombination& b, + const LinearCombination& c, + const ::std::string& name) { + pb_->addRank1Constraint(a, b, c, name); +} + +/***********************************/ +/*** R1P_Gadget ***/ +/***********************************/ +R1P_Gadget::~R1P_Gadget() {}; + +void R1P_Gadget::addRank1Constraint(const LinearCombination& a, + const LinearCombination& b, + const LinearCombination& c, + const string& name) { + pb_->addRank1Constraint(a,b,c, name); +} + +/***********************************/ +/*** End of Gadget Interfaces ***/ +/***********************************/ + +/*************************************************************************************************/ +/*************************************************************************************************/ +/******************* ******************/ +/******************* AND Gadgets ******************/ +/******************* ******************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +AND_GadgetBase::~AND_GadgetBase() {}; + +/* + Constraint breakdown: + (1) input1 * input2 = result +*/ +BinaryAND_Gadget::BinaryAND_Gadget(ProtoboardPtr pb, + const LinearCombination& input1, + const LinearCombination& input2, + const Variable& result) + : Gadget(pb), AND_GadgetBase(pb), input1_(input1), input2_(input2), result_(result) {} + +void BinaryAND_Gadget::init() {} + +void BinaryAND_Gadget::generateConstraints() { + addRank1Constraint(input1_, input2_, result_, "result = AND(input1, input2)"); +} + +void BinaryAND_Gadget::generateWitness() { + if (val(input1_) == 1 && val(input2_) == 1) { + val(result_) = 1; + } else { + val(result_) = 0; + } +} + +/* + Constraint breakdown: + + (*) sum = sum(input[i]) - n + (1) sum * result = 0 + (2) sum * sumInverse = 1 - result + + [ AND(inputs) == 1 ] (*)==> [sum == 0] (2)==> [result == 1] + [ AND(inputs) == 0 ] (*)==> [sum != 0] (1)==> [result == 0] +*/ + +R1P_AND_Gadget::R1P_AND_Gadget(ProtoboardPtr pb, + const VariableArray &input, + const Variable &result) + : Gadget(pb), AND_GadgetBase(pb), R1P_Gadget(pb), input_(input), result_(result), + sumInverse_("sumInverse") { + GADGETLIB_ASSERT(input.size() > 0, "Attempted to create an R1P_AND_Gadget with 0 inputs."); + GADGETLIB_ASSERT(input.size() <= Fp(-1).as_ulong(), "Attempted to create R1P_AND_Gadget with too " + "many inputs. Will cause overflow!"); +} + +void R1P_AND_Gadget::init() { + const int numInputs = input_.size(); + sum_ = sum(input_) - numInputs; +} + +void R1P_AND_Gadget::generateConstraints() { + addRank1Constraint(sum_, result_, 0, + "sum * result = 0 | sum == sum(input[i]) - n"); + addRank1Constraint(sumInverse_, sum_, 1-result_, + "sumInverse * sum = 1-result | sum == sum(input[i]) - n"); +} + +void R1P_AND_Gadget::generateWitness() { + FElem sum = 0; + for(size_t i = 0; i < input_.size(); ++i) { + sum += val(input_[i]); + } + sum -= input_.size(); // sum(input[i]) - n ==> sum + if (sum == 0) { // AND(input[0], input[1], ...) == 1 + val(sumInverse_) = 0; + val(result_) = 1; + } else { // AND(input[0], input[1], ...) == 0 + val(sumInverse_) = sum.inverse(R1P); + val(result_) = 0; + } +} + +GadgetPtr AND_Gadget::create(ProtoboardPtr pb, const VariableArray& input, const Variable& result){ + GadgetPtr pGadget; + if (pb->fieldType_ == R1P) { + pGadget.reset(new R1P_AND_Gadget(pb, input, result)); + } else { + GADGETLIB_FATAL("Attempted to create gadget of undefined Protoboard type."); + } + pGadget->init(); + return pGadget; +} + +GadgetPtr AND_Gadget::create(ProtoboardPtr pb, + const LinearCombination& input1, + const LinearCombination& input2, + const Variable& result) { + GadgetPtr pGadget(new BinaryAND_Gadget(pb, input1, input2, result)); + pGadget->init(); + return pGadget; +} + +/***********************************/ +/*** End of AND Gadgets ***/ +/***********************************/ + +/*************************************************************************************************/ +/*************************************************************************************************/ +/******************* ******************/ +/******************* OR Gadgets ******************/ +/******************* ******************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +OR_GadgetBase::~OR_GadgetBase() {}; + +/* + Constraint breakdown: + (1) result = input1 + input2 - input1 * input2 + input1 * input2 = input1 + input2 - result +*/ +BinaryOR_Gadget::BinaryOR_Gadget(ProtoboardPtr pb, + const LinearCombination& input1, + const LinearCombination& input2, + const Variable& result) + : Gadget(pb), OR_GadgetBase(pb), input1_(input1), input2_(input2), result_(result) {} + +void BinaryOR_Gadget::init() {} + +void BinaryOR_Gadget::generateConstraints() { + addRank1Constraint(input1_, input2_, input1_ + input2_ - result_, + "result = OR(input1, input2)"); +} + +void BinaryOR_Gadget::generateWitness() { + if (val(input1_) == 1 || val(input2_) == 1) { + val(result_) = 1; + } else { + val(result_) = 0; + } +} + +/* + Constraint breakdown: + + (*) sum = sum(input[i]) + (1) sum * (1 - result) = 0 + (2) sum * sumInverse = result + + [ OR(inputs) == 1 ] (*)==> [sum != 0] (1)==> [result == 1] + [ OR(inputs) == 0 ] (*)==> [sum == 0] (2)==> [result == 0] +*/ + +R1P_OR_Gadget::R1P_OR_Gadget(ProtoboardPtr pb, + const VariableArray &input, + const Variable &result) + : Gadget(pb), OR_GadgetBase(pb), R1P_Gadget(pb), sumInverse_("sumInverse"), input_(input), + result_(result) { + GADGETLIB_ASSERT(input.size() > 0, "Attempted to create an R1P_OR_Gadget with 0 inputs."); + GADGETLIB_ASSERT(input.size() <= Fp(-1).as_ulong(), "Attempted to create R1P_OR_Gadget with too " + "many inputs. Will cause overflow!"); + + } + +void R1P_OR_Gadget::init() { + sum_ = sum(input_); +} + +void R1P_OR_Gadget::generateConstraints() { + addRank1Constraint(sum_, 1 - result_, 0, + "sum * (1 - result) = 0 | sum == sum(input[i])"); + addRank1Constraint(sumInverse_, sum_, result_, + "sum * sumInverse = result | sum == sum(input[i])"); +} + +void R1P_OR_Gadget::generateWitness() { + FElem sum = 0; + for(size_t i = 0; i < input_.size(); ++i) { // sum(input[i]) ==> sum + sum += val(input_[i]); + } + if (sum == 0) { // OR(input[0], input[1], ...) == 0 + val(sumInverse_) = 0; + val(result_) = 0; + } else { // OR(input[0], input[1], ...) == 1 + val(sumInverse_) = sum.inverse(R1P); + val(result_) = 1; + } +} + +GadgetPtr OR_Gadget::create(ProtoboardPtr pb, const VariableArray& input, const Variable& result) { + GadgetPtr pGadget; + if (pb->fieldType_ == R1P) { + pGadget.reset(new R1P_OR_Gadget(pb, input, result)); + } else { + GADGETLIB_FATAL("Attempted to create gadget of undefined Protoboard type."); + } + pGadget->init(); + return pGadget; +} + +GadgetPtr OR_Gadget::create(ProtoboardPtr pb, + const LinearCombination& input1, + const LinearCombination& input2, + const Variable& result) { + GadgetPtr pGadget(new BinaryOR_Gadget(pb, input1, input2, result)); + pGadget->init(); + return pGadget; +} + +/***********************************/ +/*** End of OR Gadgets ***/ +/***********************************/ + +/*************************************************************************************************/ +/*************************************************************************************************/ +/******************* ******************/ +/******************* InnerProduct Gadgets ******************/ +/******************* ******************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +InnerProduct_GadgetBase::~InnerProduct_GadgetBase() {}; + +/* + Constraint breakdown: + + (1) partialSums[0] = A[0] * B[0] + (2) partialSums[i] = partialSums[i-1] + A[0] * B[0] ==> i = 1..n-2 + partialSums[i] - partialSums[i-1] = A[i] * B[i] + (3) result = partialSums[n-1] = partialSums[n-2] + A[n-1] * B[n-1] ==> + result - partialSums[n-2] = A[n-1] * B[n-1] + +*/ + +R1P_InnerProduct_Gadget::R1P_InnerProduct_Gadget(ProtoboardPtr pb, + const VariableArray& A, + const VariableArray& B, + const Variable& result) + : Gadget(pb), InnerProduct_GadgetBase(pb), R1P_Gadget(pb), partialSums_(A.size(), + "partialSums"), A_(A), B_(B), result_(result) { + GADGETLIB_ASSERT(A.size() > 0, "Attempted to create an R1P_InnerProduct_Gadget with 0 inputs."); + GADGETLIB_ASSERT(A.size() == B.size(), GADGETLIB2_FMT("Inner product vector sizes not equal. Sizes are: " + "(A) - %u, (B) - %u", A.size(), B.size())); +} + +void R1P_InnerProduct_Gadget::init() {} + +void R1P_InnerProduct_Gadget::generateConstraints() { + const int n = A_.size(); + if (n == 1) { + addRank1Constraint(A_[0], B_[0], result_, "A[0] * B[0] = result"); + return; + } + // else (n > 1) + addRank1Constraint(A_[0], B_[0], partialSums_[0], "A[0] * B[0] = partialSums[0]"); + for(int i = 1; i <= n-2; ++i) { + addRank1Constraint(A_[i], B_[i], partialSums_[i] - partialSums_[i-1], + GADGETLIB2_FMT("A[%u] * B[%u] = partialSums[%u] - partialSums[%u]", i, i, i, i-1)); + } + addRank1Constraint(A_[n-1], B_[n-1], result_ - partialSums_[n-2], + "A[n-1] * B[n-1] = result - partialSums[n-2]"); +} + +void R1P_InnerProduct_Gadget::generateWitness() { + const int n = A_.size(); + if (n == 1) { + val(result_) = val(A_[0]) * val(B_[0]); + return; + } + // else (n > 1) + val(partialSums_[0]) = val(A_[0]) * val(B_[0]); + for(int i = 1; i <= n-2; ++i) { + val(partialSums_[i]) = val(partialSums_[i-1]) + val(A_[i]) * val(B_[i]); + } + val(result_) = val(partialSums_[n-2]) + val(A_[n-1]) * val(B_[n-1]); +} + +/***********************************/ +/*** End of InnerProduct Gadgets ***/ +/***********************************/ + +/*************************************************************************************************/ +/*************************************************************************************************/ +/******************* ******************/ +/******************* LooseMUX Gadgets ******************/ +/******************* ******************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +LooseMUX_GadgetBase::~LooseMUX_GadgetBase() {}; + +/* + Constraint breakdown: + (1) indicators[i] * (index - i) = 0 | i = 0..n-1 ==> only indicators[index] will be non-zero + (2) sum(indicators[i]) = successFlag ==> successFlag = indicators[index] + (3) successFlag is boolean + (4) result[j] = * | j = 1..output.size() ==> + result[j] = inputs[index][j] + +*/ + +R1P_LooseMUX_Gadget::R1P_LooseMUX_Gadget(ProtoboardPtr pb, + const MultiPackedWordArray& inputs, + const Variable& index, + const VariableArray& output, + const Variable& successFlag) + : Gadget(pb), LooseMUX_GadgetBase(pb), R1P_Gadget(pb), + indicators_(inputs.size(), "indicators"), inputs_(inputs.size()), index_(index), + output_(output), successFlag_(successFlag) { + GADGETLIB_ASSERT(inputs.size() <= Fp(-1).as_ulong(), "Attempted to create R1P_LooseMUX_Gadget " + "with too many inputs. May cause overflow!"); +// for(const VariableArray& inpArr : inputs) { + for(size_t i = 0; i < inputs.size(); ++i) { + GADGETLIB_ASSERT(inputs[i].size() == output.size(), "Input VariableArray is of incorrect size."); + } + ::std::copy(inputs.begin(), inputs.end(), inputs_.begin()); // change type to R1P_VariableArray +} + +void R1P_LooseMUX_Gadget::init() { + // create inputs for the inner products and initialize them. Each iteration creates a + // VariableArray for the i'th elements from each of the vector's VariableArrays. + for(size_t i = 0; i < output_.size(); ++i) { + VariableArray curInput; + for(size_t j = 0; j < inputs_.size(); ++j) { + curInput.push_back(inputs_[j][i]); + } + computeResult_.push_back(InnerProduct_Gadget::create(pb_, indicators_, curInput, + output_[i])); + } +} + +void R1P_LooseMUX_Gadget::generateConstraints() { + const size_t n = inputs_.size(); + for(size_t i = 0; i < n; ++i) { + addRank1Constraint(indicators_[i], (index_-i), 0, + GADGETLIB2_FMT("indicators[%u] * (index - %u) = 0", i, i)); + } + addRank1Constraint(sum(indicators_), 1, successFlag_, "sum(indicators) * 1 = successFlag"); + enforceBooleanity(successFlag_); + for(auto& curGadget : computeResult_) { + curGadget->generateConstraints(); + } +} + +void R1P_LooseMUX_Gadget::generateWitness() { + const size_t n = inputs_.size(); + /* assumes that idx can be fit in ulong; true for our purposes for now */ + const size_t index = val(index_).asLong(); + const FElem arraySize = n; + for(size_t i = 0; i < n; ++i) { + val(indicators_[i]) = 0; // Redundant, but just in case. + } + if (index >= n) { // || index < 0 + val(successFlag_) = 0; + } else { // index in bounds + val(indicators_[index]) = 1; + val(successFlag_) = 1; + } + for(auto& curGadget : computeResult_) { + curGadget->generateWitness(); + } +} + +VariableArray R1P_LooseMUX_Gadget::indicatorVariables() const {return indicators_;} + +GadgetPtr LooseMUX_Gadget::create(ProtoboardPtr pb, + const MultiPackedWordArray& inputs, + const Variable& index, + const VariableArray& output, + const Variable& successFlag) { + GadgetPtr pGadget; + if (pb->fieldType_ == R1P) { + pGadget.reset(new R1P_LooseMUX_Gadget(pb, inputs, index, output, successFlag)); + } else { + GADGETLIB_FATAL("Attempted to create gadget of undefined Protoboard type."); + } + pGadget->init(); + return pGadget; +} + +/** + An overload for the private case in which we only want to multiplex one Variable. This is + usually the case in R1P. +**/ +GadgetPtr LooseMUX_Gadget::create(ProtoboardPtr pb, + const VariableArray& inputs, + const Variable& index, + const Variable& output, + const Variable& successFlag) { + MultiPackedWordArray inpVec; + for(size_t i = 0; i < inputs.size(); ++i) { + MultiPackedWord cur(pb->fieldType_); + cur.push_back(inputs[i]); + inpVec.push_back(cur); + } + VariableArray outVec; + outVec.push_back(output); + auto result = LooseMUX_Gadget::create(pb, inpVec, index, outVec, successFlag); + return result; +} + +/***********************************/ +/*** End of LooseMUX Gadgets ***/ +/***********************************/ + +/*************************************************************************************************/ +/*************************************************************************************************/ +/******************* ******************/ +/******************* CompressionPacking Gadgets ******************/ +/******************* ******************/ +/*************************************************************************************************/ +/*************************************************************************************************/ + +/* + Compression Packing gadgets have two modes, which differ in the way the witness and constraints + are created. In PACK mode gerateWitness() will take the bits and create a packed element (or + number of elements) while generateConstraints() will not enforce that bits are indeed Boolean. + In UNPACK mode generateWitness() will take the packed repreentation and unpack it to bits while + generateConstraints will in addition enforce that unpacked bits are indeed Boolean. +*/ + +CompressionPacking_GadgetBase::~CompressionPacking_GadgetBase() {}; + +/* + Constraint breakdown: + + (1) packed = sum(unpacked[i] * 2^i) + (2) (UNPACK only) unpacked[i] is Boolean. +*/ + +R1P_CompressionPacking_Gadget::R1P_CompressionPacking_Gadget(ProtoboardPtr pb, + const VariableArray& unpacked, + const VariableArray& packed, + PackingMode packingMode) + : Gadget(pb), CompressionPacking_GadgetBase(pb), R1P_Gadget(pb), packingMode_(packingMode), + unpacked_(unpacked), packed_(packed) { + const int n = unpacked.size(); + GADGETLIB_ASSERT(n > 0, "Attempted to pack 0 bits in R1P.") + GADGETLIB_ASSERT(packed.size() == 1, + "Attempted to pack into more than 1 Variable in R1P_CompressionPacking_Gadget.") + // TODO add assertion that 'n' bits can fit in the field characteristic +} + +void R1P_CompressionPacking_Gadget::init() {} + +void R1P_CompressionPacking_Gadget::generateConstraints() { + const int n = unpacked_.size(); + LinearCombination packed; + FElem two_i(R1P_Elem(1)); // Will hold 2^i + for (int i = 0; i < n; ++i) { + packed += unpacked_[i]*two_i; + two_i += two_i; + if (packingMode_ == PackingMode::UNPACK) {enforceBooleanity(unpacked_[i]);} + } + addRank1Constraint(packed_[0], 1, packed, "packed[0] = sum(2^i * unpacked[i])"); +} + +void R1P_CompressionPacking_Gadget::generateWitness() { + const int n = unpacked_.size(); + if (packingMode_ == PackingMode::PACK) { + FElem packedVal = 0; + FElem two_i(R1P_Elem(1)); // will hold 2^i + for(int i = 0; i < n; ++i) { + GADGETLIB_ASSERT(val(unpacked_[i]).asLong() == 0 || val(unpacked_[i]).asLong() == 1, + GADGETLIB2_FMT("unpacked[%u] = %u. Expected a Boolean value.", i, + val(unpacked_[i]).asLong())); + packedVal += two_i * val(unpacked_[i]).asLong(); + two_i += two_i; + } + val(packed_[0]) = packedVal; + return; + } + // else (UNPACK) + GADGETLIB_ASSERT(packingMode_ == PackingMode::UNPACK, "Packing gadget created with unknown packing mode."); + for(int i = 0; i < n; ++i) { + val(unpacked_[i]) = val(packed_[0]).getBit(i, R1P); + } +} + +/*****************************************/ +/*** End of CompressionPacking Gadgets ***/ +/*****************************************/ + +/*************************************************************************************************/ +/*************************************************************************************************/ +/******************* ******************/ +/******************* IntegerPacking Gadgets ******************/ +/******************* ******************/ +/*************************************************************************************************/ +/*************************************************************************************************/ + +/* + Arithmetic Packing gadgets have two modes, which differ in the way the witness and constraints + are created. In PACK mode gerateWitness() will take the bits and create a packed element (or + number of elements) while generateConstraints() will not enforce that bits are indeed Boolean. + In UNPACK mode generateWitness() will take the packed repreentation and unpack it to bits while + generateConstraints will in addition enforce that unpacked bits are indeed Boolean. +*/ + +IntegerPacking_GadgetBase::~IntegerPacking_GadgetBase() {}; + +/* + Constraint breakdown: + + (1) packed = sum(unpacked[i] * 2^i) + (2) (UNPACK only) unpacked[i] is Boolean. +*/ + +R1P_IntegerPacking_Gadget::R1P_IntegerPacking_Gadget(ProtoboardPtr pb, + const VariableArray& unpacked, + const VariableArray& packed, + PackingMode packingMode) + : Gadget(pb), IntegerPacking_GadgetBase(pb), R1P_Gadget(pb), packingMode_(packingMode), + unpacked_(unpacked), packed_(packed) { + const int n = unpacked.size(); + GADGETLIB_ASSERT(n > 0, "Attempted to pack 0 bits in R1P.") + GADGETLIB_ASSERT(packed.size() == 1, + "Attempted to pack into more than 1 Variable in R1P_IntegerPacking_Gadget.") +} + +void R1P_IntegerPacking_Gadget::init() { + compressionPackingGadget_ = CompressionPacking_Gadget::create(pb_, unpacked_, packed_, + packingMode_); +} + +void R1P_IntegerPacking_Gadget::generateConstraints() { + compressionPackingGadget_->generateConstraints(); +} + +void R1P_IntegerPacking_Gadget::generateWitness() { + compressionPackingGadget_->generateWitness(); +} + + +/*****************************************/ +/*** End of IntegerPacking Gadgets ***/ +/*****************************************/ + +/*************************************************************************************************/ +/*************************************************************************************************/ +/******************* ******************/ +/******************* EqualsConst Gadgets ******************/ +/******************* ******************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +EqualsConst_GadgetBase::~EqualsConst_GadgetBase() {}; + +/* + Constraint breakdown: + + (1) (input - n) * result = 0 + (2) (input - n) * aux = 1 - result + + [ input == n ] (2)==> [result == 1] (aux can ake any value) + [ input != n ] (1)==> [result == 0] (aux == inverse(input - n)) +*/ + +R1P_EqualsConst_Gadget::R1P_EqualsConst_Gadget(ProtoboardPtr pb, + const FElem& n, + const LinearCombination &input, + const Variable &result) + : Gadget(pb), EqualsConst_GadgetBase(pb), R1P_Gadget(pb), n_(n), + aux_("aux (R1P_EqualsConst_Gadget)"), input_(input), result_(result) {} + +void R1P_EqualsConst_Gadget::init() {} + +void R1P_EqualsConst_Gadget::generateConstraints() { + addRank1Constraint(input_ - n_, result_, 0, "(input - n) * result = 0"); + addRank1Constraint(input_ - n_, aux_, 1 - result_, "(input - n) * aux = 1 - result"); +} + +void R1P_EqualsConst_Gadget::generateWitness() { + val(aux_) = val(input_) == n_ ? 0 : (val(input_) - n_).inverse(R1P) ; + val(result_) = val(input_) == n_ ? 1 : 0 ; +} + +/***********************************/ +/*** End of EqualsConst Gadgets ***/ +/***********************************/ + +/*************************************************************************************************/ +/*************************************************************************************************/ +/******************* ******************/ +/******************* DualWord_Gadget ******************/ +/******************* ******************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +DualWord_Gadget::DualWord_Gadget(ProtoboardPtr pb, + const DualWord& var, + PackingMode packingMode) + : Gadget(pb), var_(var), packingMode_(packingMode), packingGadget_() {} + +void DualWord_Gadget::init() { + packingGadget_ = CompressionPacking_Gadget::create(pb_, var_.unpacked(), var_.multipacked(), + packingMode_); +} + +GadgetPtr DualWord_Gadget::create(ProtoboardPtr pb, + const DualWord& var, + PackingMode packingMode) { + GadgetPtr pGadget(new DualWord_Gadget(pb, var, packingMode)); + pGadget->init(); + return pGadget; +} + +void DualWord_Gadget::generateConstraints() { + packingGadget_->generateConstraints(); +} + +void DualWord_Gadget::generateWitness() { + packingGadget_->generateWitness(); +} + +/*********************************/ +/*** END OF Gadget ***/ +/*********************************/ + +/*************************************************************************************************/ +/*************************************************************************************************/ +/******************* ******************/ +/******************* DualWordArray_Gadget ******************/ +/******************* ******************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +DualWordArray_Gadget::DualWordArray_Gadget(ProtoboardPtr pb, + const DualWordArray& vars, + PackingMode packingMode) + : Gadget(pb), vars_(vars), packingMode_(packingMode), packingGadgets_() {} + +void DualWordArray_Gadget::init() { + const UnpackedWordArray unpacked = vars_.unpacked(); + const MultiPackedWordArray packed = vars_.multipacked(); + for(size_t i = 0; i < vars_.size(); ++i) { + const auto curGadget = CompressionPacking_Gadget::create(pb_, unpacked[i], packed[i], + packingMode_); + packingGadgets_.push_back(curGadget); + } +} + +GadgetPtr DualWordArray_Gadget::create(ProtoboardPtr pb, + const DualWordArray& vars, + PackingMode packingMode) { + GadgetPtr pGadget(new DualWordArray_Gadget(pb, vars, packingMode)); + pGadget->init(); + return pGadget; +} + +void DualWordArray_Gadget::generateConstraints() { + for(auto& gadget : packingGadgets_) { + gadget->generateConstraints(); + } +} + +void DualWordArray_Gadget::generateWitness() { + for(auto& gadget : packingGadgets_) { + gadget->generateWitness(); + } +} + +/*********************************/ +/*** END OF Gadget ***/ +/*********************************/ + +/*************************************************************************************************/ +/*************************************************************************************************/ +/******************* ******************/ +/******************* Toggle_Gadget ******************/ +/******************* ******************/ +/*************************************************************************************************/ +/*************************************************************************************************/ + +/* + Constraint breakdown: + + (1) result = (1 - toggle) * zeroValue + toggle * oneValue + (rank 1 format) ==> toggle * (oneValue - zeroValue) = result - zeroValue + +*/ + +Toggle_Gadget::Toggle_Gadget(ProtoboardPtr pb, + const FlagVariable& toggle, + const LinearCombination& zeroValue, + const LinearCombination& oneValue, + const Variable& result) + : Gadget(pb), toggle_(toggle), zeroValue_(zeroValue), oneValue_(oneValue), + result_(result) {} + +GadgetPtr Toggle_Gadget::create(ProtoboardPtr pb, + const FlagVariable& toggle, + const LinearCombination& zeroValue, + const LinearCombination& oneValue, + const Variable& result) { + GadgetPtr pGadget(new Toggle_Gadget(pb, toggle, zeroValue, oneValue, result)); + pGadget->init(); + return pGadget; +} + +void Toggle_Gadget::generateConstraints() { + pb_->addRank1Constraint(toggle_, oneValue_ - zeroValue_, result_ - zeroValue_, + "result = (1 - toggle) * zeroValue + toggle * oneValue"); +} + +void Toggle_Gadget::generateWitness() { + if (val(toggle_) == 0) { + val(result_) = val(zeroValue_); + } else if (val(toggle_) == 1) { + val(result_) = val(oneValue_); + } else { + GADGETLIB_FATAL("Toggle value must be Boolean."); + } +} + + +/*********************************/ +/*** END OF Gadget ***/ +/*********************************/ + +/*************************************************************************************************/ +/*************************************************************************************************/ +/******************* ******************/ +/******************* ConditionalFlag_Gadget ******************/ +/******************* ******************/ +/*************************************************************************************************/ +/*************************************************************************************************/ + +/* + semantics: condition != 0 --> flag = 1 + condition == 0 --> flag = 0 + + Constraint breakdown: + (1) condition * not(flag) = 0 + (2) condition * auxConditionInverse = flag + + */ + +ConditionalFlag_Gadget::ConditionalFlag_Gadget(ProtoboardPtr pb, + const LinearCombination& condition, + const FlagVariable& flag) + : Gadget(pb), flag_(flag), condition_(condition), + auxConditionInverse_("ConditionalFlag_Gadget::auxConditionInverse_") {} + +GadgetPtr ConditionalFlag_Gadget::create(ProtoboardPtr pb, + const LinearCombination& condition, + const FlagVariable& flag) { + GadgetPtr pGadget(new ConditionalFlag_Gadget(pb, condition, flag)); + pGadget->init(); + return pGadget; +} + +void ConditionalFlag_Gadget::generateConstraints() { + pb_->addRank1Constraint(condition_, negate(flag_), 0, "condition * not(flag) = 0"); + pb_->addRank1Constraint(condition_, auxConditionInverse_, flag_, + "condition * auxConditionInverse = flag"); +} + +void ConditionalFlag_Gadget::generateWitness() { + if (val(condition_) == 0) { + val(flag_) = 0; + val(auxConditionInverse_) = 0; + } else { + val(flag_) = 1; + val(auxConditionInverse_) = val(condition_).inverse(fieldType()); + } +} + +/*********************************/ +/*** END OF Gadget ***/ +/*********************************/ + +/*************************************************************************************************/ +/*************************************************************************************************/ +/******************* ******************/ +/******************* LogicImplication_Gadget ******************/ +/******************* ******************/ +/*************************************************************************************************/ +/*************************************************************************************************/ + +/* + semantics: condition == 1 --> flag = 1 + + Constraint breakdown: + (1) condition * (1 - flag) = 0 + + */ + +LogicImplication_Gadget::LogicImplication_Gadget(ProtoboardPtr pb, + const LinearCombination& condition, + const FlagVariable& flag) + : Gadget(pb), flag_(flag), condition_(condition) {} + +GadgetPtr LogicImplication_Gadget::create(ProtoboardPtr pb, + const LinearCombination& condition, + const FlagVariable& flag) { + GadgetPtr pGadget(new LogicImplication_Gadget(pb, condition, flag)); + pGadget->init(); + return pGadget; +} + +void LogicImplication_Gadget::generateConstraints() { + pb_->addRank1Constraint(condition_, negate(flag_), 0, "condition * not(flag) = 0"); +} + +void LogicImplication_Gadget::generateWitness() { + if (val(condition_) == 1) { + val(flag_) = 1; + } +} + +/*********************************/ +/*** END OF Gadget ***/ +/*********************************/ + +/*************************************************************************************************/ +/*************************************************************************************************/ +/******************* ******************/ +/******************* Compare_Gadget ******************/ +/******************* ******************/ +/*************************************************************************************************/ +/*************************************************************************************************/ + +Comparison_GadgetBase::~Comparison_GadgetBase() {} + +R1P_Comparison_Gadget::R1P_Comparison_Gadget(ProtoboardPtr pb, + const size_t& wordBitSize, + const PackedWord& lhs, + const PackedWord& rhs, + const FlagVariable& less, + const FlagVariable& lessOrEqual) + : Gadget(pb), Comparison_GadgetBase(pb), R1P_Gadget(pb), wordBitSize_(wordBitSize), + lhs_(lhs), rhs_(rhs), less_(less), lessOrEqual_(lessOrEqual), + alpha_u_(wordBitSize, "alpha"), notAllZeroes_("notAllZeroes") {} + +void R1P_Comparison_Gadget::init() { + allZeroesTest_ = OR_Gadget::create(pb_, alpha_u_, notAllZeroes_); + alpha_u_.emplace_back(lessOrEqual_); + alphaDualVariablePacker_ = CompressionPacking_Gadget::create(pb_, alpha_u_,VariableArray(1,alpha_p_), PackingMode::UNPACK); +} +/* + Constraint breakdown: + + for succinctness we shall define: + (1) wordBitSize == n + (2) lhs == A + (3) rhs == B + + packed(alpha) = 2^n + B - A + not_all_zeros = OR(alpha.unpacked) + + if B - A > 0, then: alpha > 2^n, + so alpha[n] = 1 and notAllZeroes = 1 + if B - A = 0, then: alpha = 2^n, + so alpha[n] = 1 and notAllZeroes = 0 + if B - A < 0, then: 0 <= alpha <= 2^n-1 + so alpha[n] = 0 + + therefore: + (1) alpha[n] = lessOrEqual + (2) alpha[n] * notAllZeroes = less + + +*/ +void R1P_Comparison_Gadget::generateConstraints() { + enforceBooleanity(notAllZeroes_); + const FElem two_n = long(POW2(wordBitSize_)); + addRank1Constraint(1, alpha_p_, two_n + rhs_ - lhs_, + "packed(alpha) = 2^n + B - A"); + alphaDualVariablePacker_->generateConstraints(); + allZeroesTest_->generateConstraints(); + addRank1Constraint(1, alpha_u_[wordBitSize_], lessOrEqual_, "alpha[n] = lessOrEqual"); + addRank1Constraint(alpha_u_[wordBitSize_], notAllZeroes_, less_, + "alpha[n] * notAllZeroes = less"); +} + +void R1P_Comparison_Gadget::generateWitness() { + const FElem two_n = long(POW2(wordBitSize_)); + val(alpha_p_) = two_n + val(rhs_) - val(lhs_); + alphaDualVariablePacker_->generateWitness(); + allZeroesTest_->generateWitness(); + val(lessOrEqual_) = val(alpha_u_[wordBitSize_]); + val(less_) = val(lessOrEqual_) * val(notAllZeroes_); +} + +/*********************************/ +/*** END OF Gadget ***/ +/*********************************/ + +} // namespace gadgetlib2 diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib2/gadget.hpp b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib2/gadget.hpp new file mode 100644 index 0000000..dbd23e9 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib2/gadget.hpp @@ -0,0 +1,747 @@ +/** @file + ***************************************************************************** + Interfaces and basic gadgets for R1P (Rank 1 prime characteristic) + constraint systems. + + These interfaces have been designed to allow later adding other fields or constraint + structures while allowing high level design to stay put. + + A gadget represents (and generates) the constraints, constraint "wiring", and + witness for a logical task. This is best explained using the physical design of a printed + circuit. The Protoboard is the board on which we will "solder" our circuit. The wires + (implemented by Variables) can hold any element of the underlying field. Each constraint + enforces a relation between wires. These can be thought of as gates. + + The delegation of tasks is as follows: + + - Constructor - Allocates all Variables to a Protoboard. Creates all sub-gadgets + that will be needed and wires their inputs and outputs. + generateConstraints - Generates the constraints which define the + necessary relations between the previously allocated Variables. + + - generateWitness - Generates an assignment for all non-input Variables which is + consistent with the assignment of the input Variables and satisfies + all of the constraints. In essence, this computes the logical + function of the Gadget. + + - create - A static factory method used for construction of the Gadget. This is + used in order to create a Gadget without explicit knowledge of the + underlying algebraic field. + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef LIBSNARK_GADGETLIB2_INCLUDE_GADGETLIB2_GADGET_HPP_ +#define LIBSNARK_GADGETLIB2_INCLUDE_GADGETLIB2_GADGET_HPP_ + +#include +#include "variable.hpp" +#include "protoboard.hpp" +#include "gadgetMacros.hpp" + +namespace gadgetlib2 { + +/*************************************************************************************************/ +/*************************************************************************************************/ +/******************* ******************/ +/******************* class Gadget ******************/ +/******************* ******************/ +/*************************************************************************************************/ +/*************************************************************************************************/ + +/** + Gadget class, representing the constraints and witness generation for a logical task. + + Gadget hierarchy: + (Here and elsewhere: R1P = Rank 1 constraints over a prime-characteristic field.) + Gadgets have a somewhat cumbursome class heirarchy, for the sake of clean gadget construction. + (1) A field agnostic, concrete (as opposed to interface) gadget will derive from Gadget. For + instance NAND needs only AND and NOT and does not care about the field, thus it derives from + Gadget. + (2) Field specific interface class R1P_Gadget derives from Gadget using virtual + inheritance, in order to avoid the Dreaded Diamond problem (see + http://stackoverflow.com/a/21607/1756254 for more info) + (3) Functional interface classes such as LooseMUX_GadgetBase virtually derive from Gadget and + define special gadget functionality. For gadgets with no special interfaces we use the macro + CREATE_GADGET_BASE_CLASS() for the sake of code consistency (these gadgets can work the same + without this base class). This is an interface only and the implementation of AND_Gadget is + field specific. + (4) These field specific gadgets will have a factory class with static method create, such as + AND_Gadget::create(...) in order to agnostically create this gadget for use by a field + agnostic gadget. + (5) Concrete field dependant gadgets derive via multiple inheritance from two interfaces. + e.g. R1P_AND_Gadget derives from both AND_Gadget and R1P_Gadget. This was done to allow usage + of AND_Gadget's field agnostic create() method and R1P_Gadget's field specific val() method. +*/ +class Gadget { +private: + DISALLOW_COPY_AND_ASSIGN(Gadget); +protected: + ProtoboardPtr pb_; +public: + Gadget(ProtoboardPtr pb); + virtual void init() = 0; + /* generate constraints must have this interface, however generateWitness for some gadgets + (like CTime) will take auxiliary information (like memory contents). We do not want to force + the interface for generateWitness but do want to make sure it is never invoked from base + class. + */ + virtual void generateConstraints() = 0; + virtual void generateWitness(); // Not abstract as this method may have different signatures. + void addUnaryConstraint(const LinearCombination& a, const ::std::string& name); + void addRank1Constraint(const LinearCombination& a, + const LinearCombination& b, + const LinearCombination& c, + const ::std::string& name); + void enforceBooleanity(const Variable& var) {pb_->enforceBooleanity(var);} + FElem& val(const Variable& var) {return pb_->val(var);} + FElem val(const LinearCombination& lc) {return pb_->val(lc);} + FieldType fieldType() const {return pb_->fieldType_;} + bool flagIsSet(const FlagVariable& flag) const {return pb_->flagIsSet(flag);} +}; + +typedef ::std::shared_ptr GadgetPtr; // Not a unique_ptr because sometimes we need to cast + // these pointers for specific gadget operations. +/***********************************/ +/*** END OF CLASS DEFINITION ***/ +/***********************************/ + +/*************************************************************************************************/ +/*************************************************************************************************/ +/******************* ******************/ +/******************* Gadget Interfaces ******************/ +/******************* ******************/ +/*************************************************************************************************/ +/*************************************************************************************************/ + +/* + We use multiple inheritance in order to use much needed syntactic sugar. We want val() to be + able to return different types depending on the field so we need to differentiate the interfaces + between R1P and other fields. We also want the interfaces of specific logical gadgets + (for instance AND_Gadget which has n inputs and 1 output) in order to construct higher level + gadgets without specific knowledge of the underlying field. Both interfaces (for instance + R1P_gadget and AND_Gadget) inherit from Gadget using virtual inheritance (this means only one + instance of Gadget will be created. For a more thorough discussion on virtual inheritance see + http://www.phpcompiler.org/articles/virtualinheritance.html + */ + +class R1P_Gadget : virtual public Gadget { +public: + R1P_Gadget(ProtoboardPtr pb) : Gadget(pb) {} + virtual ~R1P_Gadget() = 0; + + virtual void addRank1Constraint(const LinearCombination& a, + const LinearCombination& b, + const LinearCombination& c, + const ::std::string& name); +private: + virtual void init() = 0; // private in order to force programmer to invoke from a Gadget* only + DISALLOW_COPY_AND_ASSIGN(R1P_Gadget); +}; // class R1P_Gadget + +/*************************************************************************************************/ +/*************************************************************************************************/ +/******************* ******************/ +/******************* AND_Gadget classes ******************/ +/******************* ******************/ +/*************************************************************************************************/ +/*************************************************************************************************/ + +CREATE_GADGET_BASE_CLASS(AND_GadgetBase); + +/// Specific case for and AND with two inputs. Field agnostic +class BinaryAND_Gadget : public AND_GadgetBase { +private: + BinaryAND_Gadget(ProtoboardPtr pb, + const LinearCombination& input1, + const LinearCombination& input2, + const Variable& result); + void init(); + void generateConstraints(); + void generateWitness(); +public: + friend class AND_Gadget; +private: + //external variables + const LinearCombination input1_; + const LinearCombination input2_; + const Variable result_; + + DISALLOW_COPY_AND_ASSIGN(BinaryAND_Gadget); +}; // class BinaryAND_Gadget + +class R1P_AND_Gadget : public AND_GadgetBase, public R1P_Gadget { +private: + R1P_AND_Gadget(ProtoboardPtr pb, const VariableArray& input, const Variable& result); + virtual void init(); +public: + void generateConstraints(); + void generateWitness(); + friend class AND_Gadget; +private: + //external variables + const VariableArray input_; + const Variable result_; + //internal variables + LinearCombination sum_; + Variable sumInverse_; + + DISALLOW_COPY_AND_ASSIGN(R1P_AND_Gadget); +}; + + +class AND_Gadget { +public: + static GadgetPtr create(ProtoboardPtr pb, const VariableArray& input, const Variable& result); + static GadgetPtr create(ProtoboardPtr pb, + const LinearCombination& input1, + const LinearCombination& input2, + const Variable& result); +private: + DISALLOW_CONSTRUCTION(AND_Gadget); + DISALLOW_COPY_AND_ASSIGN(AND_Gadget); +}; // class GadgetType + + +/*********************************/ +/*** END OF Gadget ***/ +/*********************************/ + +/*************************************************************************************************/ +/*************************************************************************************************/ +/******************* ******************/ +/******************* OR_Gadget classes ******************/ +/******************* ******************/ +/*************************************************************************************************/ +/*************************************************************************************************/ + +CREATE_GADGET_BASE_CLASS(OR_GadgetBase); + +/// Specific case for and OR with two inputs. Field agnostic +class BinaryOR_Gadget : public OR_GadgetBase { +private: + BinaryOR_Gadget(ProtoboardPtr pb, + const LinearCombination& input1, + const LinearCombination& input2, + const Variable& result); + void init(); + void generateConstraints(); + void generateWitness(); +public: + friend class OR_Gadget; +private: + //external variables + const LinearCombination input1_; + const LinearCombination input2_; + const Variable result_; + + DISALLOW_COPY_AND_ASSIGN(BinaryOR_Gadget); +}; // class BinaryOR_Gadget + +class R1P_OR_Gadget : public OR_GadgetBase, public R1P_Gadget { +private: + LinearCombination sum_; + Variable sumInverse_; + R1P_OR_Gadget(ProtoboardPtr pb, const VariableArray& input, const Variable& result); + virtual void init(); +public: + const VariableArray input_; + const Variable result_; + void generateConstraints(); + void generateWitness(); + friend class OR_Gadget; +private: + DISALLOW_COPY_AND_ASSIGN(R1P_OR_Gadget); +}; + +class OR_Gadget { +public: + static GadgetPtr create(ProtoboardPtr pb, const VariableArray& input, const Variable& result); + static GadgetPtr create(ProtoboardPtr pb, + const LinearCombination& input1, + const LinearCombination& input2, + const Variable& result); +private: + DISALLOW_CONSTRUCTION(OR_Gadget); + DISALLOW_COPY_AND_ASSIGN(OR_Gadget); +}; // class GadgetType + +/*********************************/ +/*** END OF Gadget ***/ +/*********************************/ + +/*************************************************************************************************/ +/*************************************************************************************************/ +/******************* ******************/ +/******************* InnerProduct_Gadget classes ******************/ +/******************* ******************/ +/*************************************************************************************************/ +/*************************************************************************************************/ + +CREATE_GADGET_BASE_CLASS(InnerProduct_GadgetBase); + +class R1P_InnerProduct_Gadget : public InnerProduct_GadgetBase, public R1P_Gadget { +private: + VariableArray partialSums_; + R1P_InnerProduct_Gadget(ProtoboardPtr pb, + const VariableArray& A, + const VariableArray& B, + const Variable& result); + virtual void init(); +public: + const VariableArray A_, B_; + const Variable result_; + void generateConstraints(); + void generateWitness(); + friend class InnerProduct_Gadget; +private: + DISALLOW_COPY_AND_ASSIGN(R1P_InnerProduct_Gadget); +}; + +CREATE_GADGET_FACTORY_CLASS_3(InnerProduct_Gadget, VariableArray, A, + VariableArray, B, + Variable, result); + +/*********************************/ +/*** END OF Gadget ***/ +/*********************************/ + +/*************************************************************************************************/ +/*************************************************************************************************/ +/******************* ******************/ +/******************* LooseMUX_Gadget classes ******************/ +/******************* ******************/ +/*************************************************************************************************/ +/*************************************************************************************************/ + +/* + Loose Multiplexer (MUX): + Multiplexes one Variable + index not in bounds -> success_flag = 0 + index in bounds && success_flag = 1 -> result is correct + index is in bounds, we can also set success_flag to 0 -> result will be forced to 0 +*/ + +class LooseMUX_GadgetBase : virtual public Gadget { +protected: + LooseMUX_GadgetBase(ProtoboardPtr pb) : Gadget(pb) {} +public: + virtual ~LooseMUX_GadgetBase() = 0; + virtual VariableArray indicatorVariables() const = 0; +private: + virtual void init() = 0; + DISALLOW_COPY_AND_ASSIGN(LooseMUX_GadgetBase); +}; // class LooseMUX_GadgetBase + + +class R1P_LooseMUX_Gadget : public LooseMUX_GadgetBase, public R1P_Gadget { +private: + VariableArray indicators_; + ::std::vector computeResult_; // Inner product gadgets + R1P_LooseMUX_Gadget(ProtoboardPtr pb, + const MultiPackedWordArray& inputs, + const Variable& index, + const VariableArray& output, + const Variable& successFlag); + virtual void init(); +public: + MultiPackedWordArray inputs_; + const Variable index_; + const VariableArray output_; + const Variable successFlag_; + void generateConstraints(); + void generateWitness(); + virtual VariableArray indicatorVariables() const; + friend class LooseMUX_Gadget; +private: + DISALLOW_COPY_AND_ASSIGN(R1P_LooseMUX_Gadget); +}; + +class LooseMUX_Gadget { +public: + static GadgetPtr create(ProtoboardPtr pb, + const MultiPackedWordArray& inputs, + const Variable& index, + const VariableArray& output, + const Variable& successFlag); + static GadgetPtr create(ProtoboardPtr pb, + const VariableArray& inputs, + const Variable& index, + const Variable& output, + const Variable& successFlag); +private: + DISALLOW_CONSTRUCTION(LooseMUX_Gadget); + DISALLOW_COPY_AND_ASSIGN(LooseMUX_Gadget); +}; // class GadgetType + + +/*********************************/ +/*** END OF Gadget ***/ +/*********************************/ + +/*************************************************************************************************/ +/*************************************************************************************************/ +/******************* ******************/ +/******************* CompressionPacking_Gadget classes ******************/ +/******************* ******************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +// TODO change class name to bitpacking +enum class PackingMode : bool {PACK, UNPACK}; + +CREATE_GADGET_BASE_CLASS(CompressionPacking_GadgetBase); + +class R1P_CompressionPacking_Gadget : public CompressionPacking_GadgetBase, public R1P_Gadget { +private: + PackingMode packingMode_; + R1P_CompressionPacking_Gadget(ProtoboardPtr pb, + const VariableArray& unpacked, + const VariableArray& packed, + PackingMode packingMode); + virtual void init(); +public: + const VariableArray unpacked_; + const VariableArray packed_; + void generateConstraints(); + void generateWitness(); + friend class CompressionPacking_Gadget; +private: + DISALLOW_COPY_AND_ASSIGN(R1P_CompressionPacking_Gadget); +}; + +CREATE_GADGET_FACTORY_CLASS_3(CompressionPacking_Gadget, VariableArray, unpacked, VariableArray, + packed, PackingMode, packingMode); + + +/*********************************/ +/*** END OF Gadget ***/ +/*********************************/ + +/*************************************************************************************************/ +/*************************************************************************************************/ +/******************* ******************/ +/******************* IntegerPacking_Gadget classes ******************/ +/******************* ******************/ +/*************************************************************************************************/ +/*************************************************************************************************/ + +CREATE_GADGET_BASE_CLASS(IntegerPacking_GadgetBase); + +// In R1P compression and arithmetic packing are implemented the same, hence this gadget simply +// instantiates an R1P_CompressionPacking_Gadget +class R1P_IntegerPacking_Gadget : public IntegerPacking_GadgetBase, public R1P_Gadget { +private: + PackingMode packingMode_; + GadgetPtr compressionPackingGadget_; + R1P_IntegerPacking_Gadget(ProtoboardPtr pb, + const VariableArray& unpacked, + const VariableArray& packed, + PackingMode packingMode); + virtual void init(); +public: + const VariableArray unpacked_; + const VariableArray packed_; + void generateConstraints(); + void generateWitness(); + friend class IntegerPacking_Gadget; +private: + DISALLOW_COPY_AND_ASSIGN(R1P_IntegerPacking_Gadget); +}; + +CREATE_GADGET_FACTORY_CLASS_3(IntegerPacking_Gadget, VariableArray, unpacked, VariableArray, + packed, PackingMode, packingMode); + +/*********************************/ +/*** END OF Gadget ***/ +/*********************************/ + +/*************************************************************************************************/ +/*************************************************************************************************/ +/******************* ******************/ +/******************* EqualsConst_Gadget classes ******************/ +/******************* ******************/ +/*************************************************************************************************/ +/*************************************************************************************************/ + +/* + Gadgets recieve a constant field element n, and an input. + input == n ==> result = 1 + input != n ==> result = 0 +*/ + +// TODO change to take LinearCombination as input and change AND/OR to use this +CREATE_GADGET_BASE_CLASS(EqualsConst_GadgetBase); + +class R1P_EqualsConst_Gadget : public EqualsConst_GadgetBase, public R1P_Gadget { +private: + const FElem n_; + Variable aux_; + R1P_EqualsConst_Gadget(ProtoboardPtr pb, + const FElem& n, + const LinearCombination& input, + const Variable& result); + virtual void init(); +public: + const LinearCombination input_; + const Variable result_; + void generateConstraints(); + void generateWitness(); + friend class EqualsConst_Gadget; +private: + DISALLOW_COPY_AND_ASSIGN(R1P_EqualsConst_Gadget); +}; + +CREATE_GADGET_FACTORY_CLASS_3(EqualsConst_Gadget, FElem, n, LinearCombination, input, + Variable, result); + +/*********************************/ +/*** END OF Gadget ***/ +/*********************************/ + +/*************************************************************************************************/ +/*************************************************************************************************/ +/******************* ******************/ +/******************* DualWord_Gadget ******************/ +/******************* ******************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +//TODO add test + +class DualWord_Gadget : public Gadget { + +private: + const DualWord var_; + const PackingMode packingMode_; + + GadgetPtr packingGadget_; + + DualWord_Gadget(ProtoboardPtr pb, const DualWord& var, PackingMode packingMode); + virtual void init(); + DISALLOW_COPY_AND_ASSIGN(DualWord_Gadget); +public: + static GadgetPtr create(ProtoboardPtr pb, const DualWord& var, PackingMode packingMode); + void generateConstraints(); + void generateWitness(); +}; + +/*********************************/ +/*** END OF Gadget ***/ +/*********************************/ + +/*************************************************************************************************/ +/*************************************************************************************************/ +/******************* ******************/ +/******************* DualWordArray_Gadget ******************/ +/******************* ******************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +//TODO add test + +class DualWordArray_Gadget : public Gadget { + +private: + const DualWordArray vars_; + const PackingMode packingMode_; + + ::std::vector packingGadgets_; + + DualWordArray_Gadget(ProtoboardPtr pb, + const DualWordArray& vars, + PackingMode packingMode); + virtual void init(); + DISALLOW_COPY_AND_ASSIGN(DualWordArray_Gadget); +public: + static GadgetPtr create(ProtoboardPtr pb, + const DualWordArray& vars, + PackingMode packingMode); + void generateConstraints(); + void generateWitness(); +}; + +/*********************************/ +/*** END OF Gadget ***/ +/*********************************/ + +/*************************************************************************************************/ +/*************************************************************************************************/ +/******************* ******************/ +/******************* Toggle_Gadget ******************/ +/******************* ******************/ +/*************************************************************************************************/ +/*************************************************************************************************/ + +//TODO add test + +/// A gadget for the following semantics: +/// If toggle is 0, zeroValue --> result +/// If toggle is 1, oneValue --> result +/// Uses 1 constraint + +class Toggle_Gadget : public Gadget { +private: + FlagVariable toggle_; + LinearCombination zeroValue_; + LinearCombination oneValue_; + Variable result_; + + Toggle_Gadget(ProtoboardPtr pb, + const FlagVariable& toggle, + const LinearCombination& zeroValue, + const LinearCombination& oneValue, + const Variable& result); + + virtual void init() {} + DISALLOW_COPY_AND_ASSIGN(Toggle_Gadget); +public: + static GadgetPtr create(ProtoboardPtr pb, + const FlagVariable& toggle, + const LinearCombination& zeroValue, + const LinearCombination& oneValue, + const Variable& result); + + void generateConstraints(); + void generateWitness(); +}; + +/*********************************/ +/*** END OF Gadget ***/ +/*********************************/ + + +/*************************************************************************************************/ +/*************************************************************************************************/ +/******************* ******************/ +/******************* ConditionalFlag_Gadget ******************/ +/******************* ******************/ +/*************************************************************************************************/ +/*************************************************************************************************/ + +/// A gadget for the following semantics: +/// condition != 0 --> flag = 1 +/// condition == 0 --> flag = 0 +/// Uses 2 constraints + +class ConditionalFlag_Gadget : public Gadget { +private: + FlagVariable flag_; + LinearCombination condition_; + Variable auxConditionInverse_; + + ConditionalFlag_Gadget(ProtoboardPtr pb, + const LinearCombination& condition, + const FlagVariable& flag); + + virtual void init() {} + DISALLOW_COPY_AND_ASSIGN(ConditionalFlag_Gadget); +public: + static GadgetPtr create(ProtoboardPtr pb, + const LinearCombination& condition, + const FlagVariable& flag); + + void generateConstraints(); + void generateWitness(); +}; + +/*********************************/ +/*** END OF Gadget ***/ +/*********************************/ + +/*************************************************************************************************/ +/*************************************************************************************************/ +/******************* ******************/ +/******************* LogicImplication_Gadget ******************/ +/******************* ******************/ +/*************************************************************************************************/ +/*************************************************************************************************/ + +/// A gadget for the following semantics: +/// condition == 1 --> flag = 1 +/// Uses 1 constraint + +class LogicImplication_Gadget : public Gadget { +private: + FlagVariable flag_; + LinearCombination condition_; + + LogicImplication_Gadget(ProtoboardPtr pb, + const LinearCombination& condition, + const FlagVariable& flag); + + virtual void init() {} + DISALLOW_COPY_AND_ASSIGN(LogicImplication_Gadget); +public: + static GadgetPtr create(ProtoboardPtr pb, + const LinearCombination& condition, + const FlagVariable& flag); + + void generateConstraints(); + void generateWitness(); +}; + +/*********************************/ +/*** END OF Gadget ***/ +/*********************************/ + +/*************************************************************************************************/ +/*************************************************************************************************/ +/******************* ******************/ +/******************* Compare_Gadget ******************/ +/******************* ******************/ +/*************************************************************************************************/ +/*************************************************************************************************/ + +// TODO create unit test +CREATE_GADGET_BASE_CLASS(Comparison_GadgetBase); + +class R1P_Comparison_Gadget : public Comparison_GadgetBase, public R1P_Gadget { +private: + const size_t wordBitSize_; + const PackedWord lhs_; + const PackedWord rhs_; + const FlagVariable less_; + const FlagVariable lessOrEqual_; + const PackedWord alpha_p_; + UnpackedWord alpha_u_; + const FlagVariable notAllZeroes_; + GadgetPtr allZeroesTest_; + GadgetPtr alphaDualVariablePacker_; + + R1P_Comparison_Gadget(ProtoboardPtr pb, + const size_t& wordBitSize, + const PackedWord& lhs, + const PackedWord& rhs, + const FlagVariable& less, + const FlagVariable& lessOrEqual); + virtual void init(); +public: + + static GadgetPtr create(ProtoboardPtr pb, + const size_t& wordBitSize, + const PackedWord& lhs, + const PackedWord& rhs, + const FlagVariable& less, + const FlagVariable& lessOrEqual); + + void generateConstraints(); + void generateWitness(); + friend class Comparison_Gadget; +private: + DISALLOW_COPY_AND_ASSIGN(R1P_Comparison_Gadget); +}; + +CREATE_GADGET_FACTORY_CLASS_5(Comparison_Gadget, // TODO uncomment this + size_t, wordBitSize, + PackedWord, lhs, + PackedWord, rhs, + FlagVariable, less, + FlagVariable, lessOrEqual); + +/*********************************/ +/*** END OF Gadget ***/ +/*********************************/ + +} // namespace gadgetlib2 + +#endif // LIBSNARK_GADGETLIB2_INCLUDE_GADGETLIB2_GADGET_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib2/gadgetMacros.hpp b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib2/gadgetMacros.hpp new file mode 100644 index 0000000..eed8f99 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib2/gadgetMacros.hpp @@ -0,0 +1,284 @@ +/** @file + ***************************************************************************** + Macros for quick construction of interface and factory classes for non field + agnostic gadgets. + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef LIBSNARK_GADGETLIB2_INCLUDE_GADGETLIB2_GADGETMACROS_HPP_ +#define LIBSNARK_GADGETLIB2_INCLUDE_GADGETLIB2_GADGETMACROS_HPP_ + +// The macro below counts the number of arguments sent with __VA_ARGS__ +// it has not been tested yet. Due to a current MSVC bug it is not in use yet. + +///* The PP_NARG macro returns the number of arguments that have been +// * passed to it. +// */ + +/* +//#define PP_NARG(...) \ +// PP_NARG_(__VA_ARGS__,PP_RSEQ_N()) +//#define PP_NARG_(...) \ +// PP_ARG_N(__VA_ARGS__) +//#define PP_ARG_N( \ +// _1, _2, _3, _4, _5, _6, _7, _8, _9,_10, \ +// _11,_12,_13,_14,_15,_16,_17,_18,_19,_20, \ +// _21,_22,_23,_24,_25,_26,_27,_28,_29,_30, \ +// _31,_32,_33,_34,_35,_36,_37,_38,_39,_40, \ +// _41,_42,_43,_44,_45,_46,_47,_48,_49,_50, \ +// _51,_52,_53,_54,_55,_56,_57,_58,_59,_60, \ +// _61,_62,_63,N,...) N +//#define PP_RSEQ_N() \ +// 63,62,61,60, \ +// 59,58,57,56,55,54,53,52,51,50, \ +// 49,48,47,46,45,44,43,42,41,40, \ +// 39,38,37,36,35,34,33,32,31,30, \ +// 29,28,27,26,25,24,23,22,21,20, \ +// 19,18,17,16,15,14,13,12,11,10, \ +// 9,8,7,6,5,4,3,2,1,0 +*/ + +/** + Macro which creates Base classes for function specific gadgets. For instance + CREATE_GADGET_BASE_CLASS(AND_GadgetBase) will create a base class which should be inherited by + R1P_AND_Gadget and ANOTHER_FIELD_AND_Gadget. The Factory class which makes a field agnostic + gadget will be created by the CREATE_GADGET_FACTORY_CLASS(AND_Gadget, ...) macro +*/ +#define CREATE_GADGET_BASE_CLASS(GadgetBase) \ +class GadgetBase : virtual public Gadget { \ +protected: \ + GadgetBase(ProtoboardPtr pb) : Gadget(pb) {} \ +public: \ + virtual ~GadgetBase() = 0; \ +private: \ + virtual void init() = 0; \ + DISALLOW_COPY_AND_ASSIGN(GadgetBase); \ +}; // class GadgetBase + + + +/** + Macro for creating gadget factory classes. For instance + CREATE_GADGET_FACTORY_CLASS(AND_Gadget, 2, VariableArray, input, Variable, result); creates a + class AND_Gadget with the method: + GadgetPtr AND_Gadget::create(ProtoboardPtr pb, + const VariableArray& input, + const Variable& result) + which will instantiate a field specific gadget depending on the Protoboard type. + This macro implements the factory design pattern. +*/ +#define ADD_ELLIPSES_1(Type1, name1) \ + const Type1 & name1 + +#define ADD_ELLIPSES_2(Type1, name1, Type2, name2) \ + const Type1 & name1, const Type2 & name2 + +#define ADD_ELLIPSES_3(Type1, name1, Type2, name2, Type3, name3) \ + const Type1 & name1, const Type2 & name2, const Type3 & name3 + +#define ADD_ELLIPSES_4(Type1, name1, Type2, name2, Type3, name3, Type4, name4) \ + const Type1 & name1, const Type2 & name2, const Type3 & name3, const Type4 & name4 + +#define ADD_ELLIPSES_5(Type1, name1, Type2, name2, Type3, name3, Type4, name4, Type5, name5) \ + const Type1 & name1, const Type2 & name2, const Type3 & name3, const Type4 & name4, \ + const Type5 & name5 + +#define ADD_ELLIPSES_7(Type1, name1, Type2, name2, Type3, name3, Type4, name4, Type5, name5, \ + Type6, name6, Type7, name7, Type8, name8, Type9, name9) \ + const Type1 & name1, const Type2 & name2, const Type3 & name3, const Type4 & name4, \ + const Type5 & name5, const Type6 & name6, const Type7 & name7 + +#define ADD_ELLIPSES_8(Type1, name1, Type2, name2, Type3, name3, Type4, name4, Type5, name5, \ + Type6, name6, Type7, name7, Type8, name8) \ + const Type1 & name1, const Type2 & name2, const Type3 & name3, const Type4 & name4, \ + const Type5 & name5, const Type6 & name6, const Type7 & name7, const Type8 & name8 + +#define ADD_ELLIPSES_9(Type1, name1, Type2, name2, Type3, name3, Type4, name4, Type5, name5, \ + Type6, name6, Type7, name7, Type8, name8, Type9, name9) \ + const Type1 & name1, const Type2 & name2, const Type3 & name3, const Type4 & name4, \ + const Type5 & name5, const Type6 & name6, const Type7 & name7, const Type8 & name8, \ + const Type9 & name9 + +/* + This was supposed to be a variadic macro CREATE_GADGET_FACTORY_CLASS(...) which invokes the + correct number of arguments. Due to an MSVC bug and lack of time it will currently be copied + with different names. + Hopefully some day I will have time to find a workaround / use Boost preprocessor instead. + The MSVC bug (feature...) is that __VA_ARGS__ passes to sub macros as 1 argument, so defining + the following: + #define CREATE_GADGET_FACTORY_CLASS(__VA_ARGS__) \ + CREATE_GADGET_FACTORY_CLASS_ ## PP_NARG(__VA_ARGS__)(__VA_ARGS__) + will always create CREATE_GADGET_FACTORY_CLASS_1(__VA_ARGS__) + Moreover, this macro considers __VA_ARGS__ to be only 1 argument! +*/ +#define CREATE_GADGET_FACTORY_CLASS_1(GadgetType, Type1, name1) \ +class GadgetType { \ +public: \ + static GadgetPtr create(ProtoboardPtr pb, ADD_ELLIPSES_1(Type1, name1)) { \ + GadgetPtr pGadget; \ + if (pb->fieldType_ == R1P) { \ + pGadget.reset(new R1P_ ## GadgetType(pb, name1)); \ + } else { \ + GADGETLIB_FATAL("Attempted to create gadget of undefined Protoboard type."); \ + } \ + pGadget->init(); \ + return pGadget; \ + } \ +private: \ + DISALLOW_CONSTRUCTION(GadgetType); \ + DISALLOW_COPY_AND_ASSIGN(GadgetType); \ +}; // class GadgetType + +#define CREATE_GADGET_FACTORY_CLASS_2(GadgetType, Type1, name1, Type2, name2) \ +class GadgetType { \ +public: \ + static GadgetPtr create(ProtoboardPtr pb, \ + ADD_ELLIPSES_2(Type1, name1, Type2, name2)) { \ + GadgetPtr pGadget; \ + if (pb->fieldType_ == R1P) { \ + pGadget.reset(new R1P_ ## GadgetType(pb, name1, name2)); \ + } else { \ + GADGETLIB_FATAL("Attempted to create gadget of undefined Protoboard type."); \ + } \ + pGadget->init(); \ + return pGadget; \ + } \ +private: \ + DISALLOW_CONSTRUCTION(GadgetType); \ + DISALLOW_COPY_AND_ASSIGN(GadgetType); \ +}; // class GadgetType + +#define CREATE_GADGET_FACTORY_CLASS_3(GadgetType, Type1, name1, Type2, name2, Type3, name3) \ +class GadgetType { \ +public: \ + static GadgetPtr create(ProtoboardPtr pb, \ + ADD_ELLIPSES_3(Type1, name1, Type2, name2, Type3, name3)) { \ + GadgetPtr pGadget; \ + if (pb->fieldType_ == R1P) { \ + pGadget.reset(new R1P_ ## GadgetType(pb, name1, name2, name3)); \ + } else { \ + GADGETLIB_FATAL("Attempted to create gadget of undefined Protoboard type."); \ + } \ + pGadget->init(); \ + return pGadget; \ + } \ +private: \ + DISALLOW_CONSTRUCTION(GadgetType); \ + DISALLOW_COPY_AND_ASSIGN(GadgetType); \ +}; // class GadgetType + +#define CREATE_GADGET_FACTORY_CLASS_4(GadgetType, Type1, name1, Type2, name2, Type3, name3, \ + Type4, name4) \ +class GadgetType { \ +public: \ + static GadgetPtr create(ProtoboardPtr pb, \ + ADD_ELLIPSES_4(Type1, name1, Type2, name2, Type3, name3, Type4, name4)) { \ + GadgetPtr pGadget; \ + if (pb->fieldType_ == R1P) { \ + pGadget.reset(new R1P_ ## GadgetType(pb, name1, name2, name3, name4)); \ + } else { \ + GADGETLIB_FATAL("Attempted to create gadget of undefined Protoboard type."); \ + } \ + pGadget->init(); \ + return pGadget; \ + } \ +private: \ + DISALLOW_CONSTRUCTION(GadgetType); \ + DISALLOW_COPY_AND_ASSIGN(GadgetType); \ +}; // class GadgetType + +#define CREATE_GADGET_FACTORY_CLASS_5(GadgetType, Type1, name1, Type2, name2, Type3, name3, \ + Type4, name4, Type5, name5) \ +class GadgetType { \ +public: \ + static GadgetPtr create(ProtoboardPtr pb, \ + ADD_ELLIPSES_5(Type1, name1, Type2, name2, Type3, name3, Type4, name4, \ + Type5, name5)) { \ + GadgetPtr pGadget; \ + if (pb->fieldType_ == R1P) { \ + pGadget.reset(new R1P_ ## GadgetType(pb, name1, name2, name3, name4, name5)); \ + } else { \ + GADGETLIB_FATAL("Attempted to create gadget of undefined Protoboard type."); \ + } \ + pGadget->init(); \ + return pGadget; \ + } \ +private: \ + DISALLOW_CONSTRUCTION(GadgetType); \ + DISALLOW_COPY_AND_ASSIGN(GadgetType); \ +}; // class GadgetType + +#define CREATE_GADGET_FACTORY_CLASS_7(GadgetType, Type1, name1, Type2, name2, Type3, name3, \ + Type4, name4, Type5, name5, Type6, name6, Type7, name7) \ +class GadgetType { \ +public: \ + static GadgetPtr create(ProtoboardPtr pb, \ + ADD_ELLIPSES_7(Type1, name1, Type2, name2, Type3, name3, Type4, name4, \ + Type5, name5, Type6, name6, Type7, name7)) { \ + GadgetPtr pGadget; \ + if (pb->fieldType_ == R1P) { \ + pGadget.reset(new R1P_ ## GadgetType(pb, name1, name2, name3, name4, name5, name6, \ + name7)); \ + } else { \ + GADGETLIB_FATAL("Attempted to create gadget of undefined Protoboard type."); \ + } \ + pGadget->init(); \ + return pGadget; \ + } \ +private: \ + DISALLOW_CONSTRUCTION(GadgetType); \ + DISALLOW_COPY_AND_ASSIGN(GadgetType); \ +}; // class GadgetType + + +#define CREATE_GADGET_FACTORY_CLASS_8(GadgetType, Type1, name1, Type2, name2, Type3, name3, \ + Type4, name4, Type5, name5, Type6, name6, Type7, name7, \ + Type8, name8) \ +class GadgetType { \ +public: \ + static GadgetPtr create(ProtoboardPtr pb, \ + ADD_ELLIPSES_8(Type1, name1, Type2, name2, Type3, name3, Type4, name4, \ + Type5, name5, Type6, name6, Type7, name7, Type8, name8)) { \ + GadgetPtr pGadget; \ + if (pb->fieldType_ == R1P) { \ + pGadget.reset(new R1P_ ## GadgetType(pb, name1, name2, name3, name4, name5, name6, \ + name7, name8)); \ + } else { \ + GADGETLIB_FATAL("Attempted to create gadget of undefined Protoboard type."); \ + } \ + pGadget->init(); \ + return pGadget; \ + } \ +private: \ + DISALLOW_CONSTRUCTION(GadgetType); \ + DISALLOW_COPY_AND_ASSIGN(GadgetType); \ +}; // class GadgetType + +#define CREATE_GADGET_FACTORY_CLASS_9(GadgetType, Type1, name1, Type2, name2, Type3, name3, \ + Type4, name4, Type5, name5, Type6, name6, Type7, name7, \ + Type8, name8, Type9, name9) \ +class GadgetType { \ +public: \ + static GadgetPtr create(ProtoboardPtr pb, \ + ADD_ELLIPSES_9(Type1, name1, Type2, name2, Type3, name3, Type4, name4, \ + Type5, name5, Type6, name6, Type7, name7, Type8, name8, \ + Type9, name9)) { \ + GadgetPtr pGadget; \ + if (pb->fieldType_ == R1P) { \ + pGadget.reset(new R1P_ ## GadgetType(pb, name1, name2, name3, name4, name5, name6, \ + name7, name8, name9)); \ + } else { \ + GADGETLIB_FATAL("Attempted to create gadget of undefined Protoboard type."); \ + } \ + pGadget->init(); \ + return pGadget; \ + } \ +private: \ + DISALLOW_CONSTRUCTION(GadgetType); \ + DISALLOW_COPY_AND_ASSIGN(GadgetType); \ +}; // class GadgetType + +#endif // LIBSNARK_GADGETLIB2_INCLUDE_GADGETLIB2_GADGETMACROS_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib2/infrastructure.cpp b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib2/infrastructure.cpp new file mode 100644 index 0000000..6df9f95 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib2/infrastructure.cpp @@ -0,0 +1,120 @@ +/** @file + ***************************************************************************** + Common functionality needed by many components. + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include "infrastructure.hpp" + +#include +#include +#include +#include +#ifdef __linux__ +#include +#endif +#ifdef __GLIBC__ +#include // backtraces +#endif + +namespace gadgetlib2 { + +/********************************************************/ +/*************** Debug String Formatting ****************/ +/********************************************************/ + +#ifdef DEBUG +const static size_t MAX_FMT = 256; +::std::string GADGETLIB2_FMT(const char* format, ...) { + char buf[MAX_FMT]; + va_list args; + va_start(args, format); +#if defined(_MSC_VER) + const int strChk = vsnprintf_s(buf, MAX_FMT, MAX_FMT, format, args); +#else + const int strChk = vsnprintf(buf, MAX_FMT, format, args); +#endif + va_end(args); + GADGETLIB_ASSERT(strChk >= 0 && strChk < MAX_FMT, "String length larger than buffer. Shorten" + " string or increase buffer size defined in \"MAX_FMT\"."); + return ::std::string(buf); +} +#else // not DEBUG +::std::string GADGETLIB2_FMT(const char* format, ...) {UNUSED(format); return "";} +#endif + +/** Safely converts 64-bit types to 32-bit. */ +long safeConvert(const int64_t num) { + assert(num <= INT_MAX && num >= INT_MIN); + return (long)num; +} + +/*****************************************************************************/ +/*********************** ErrorHandling********** ****************************/ +/*****************************************************************************/ + +/* + TODO add dumping of environment variables and run command to a log file and add log file path + to release mode error message. We don't want people running release version to get any internal + information (variable values, stack trace, etc.) but want to have every data possible to + reproduce assertion. +*/ +void ErrorHandling::fatalError(const ::std::string& msg) { +# ifdef DEBUG + ::std::cerr << "ERROR: " << msg << ::std::endl << ::std::endl; + printStacktrace(); + throw ::std::runtime_error(msg); +# else // not DEBUG + UNUSED(msg); + const ::std::string releaseMsg("Fatal error encoutered. Run debug build for more" + " information and stack trace."); + ::std::cerr << "ERROR: " << releaseMsg << ::std::endl << ::std::endl; + throw ::std::runtime_error(releaseMsg); +# endif +} + +void ErrorHandling::fatalError(const ::std::stringstream& msg) { + fatalError(msg.str()); +} + +void ErrorHandling::printStacktrace() { +#ifdef __GLIBC__ + std::cerr << "Stack trace (pipe through c++filt to demangle identifiers):" << std::endl; + const int maxFrames = 100; + void* frames[maxFrames]; + // Fill array with pointers to stack frames + int numFrames = backtrace(frames, maxFrames); + // Decode frames and print them to stderr + backtrace_symbols_fd(frames, numFrames, STDERR_FILENO); +#else + //TODO make this available for non-glibc platforms (e.g. musl libc on Linux and Windows) + std::cerr << " (stack trace not available on this platform)" << std::endl; +#endif // __GNUC__ +} + +/*****************************************************************************/ +/**************************** Basic Math ***********************************/ +/*****************************************************************************/ + +double Log2( double n ) { + return log(n) / log((double)2); +} + +/// Returns an upper bound on log2(i). Namely, returns the number of binary digits needed to store +/// the value 'i'. When i == 0 returns 0. +unsigned int Log2ceil(uint64_t i) { + int retval = i ? 1 : 0 ; + while (i >>= 1) {++retval;} + return retval; +} + +///Returns true iff x is a power of 2 +bool IsPower2(const long x) { + return ( (x > 0) && ((x & (x - 1)) == 0) ); +} + +} // namespace gadgetlib2 + diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib2/infrastructure.hpp b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib2/infrastructure.hpp new file mode 100644 index 0000000..aa5800f --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib2/infrastructure.hpp @@ -0,0 +1,125 @@ +/** @file + ***************************************************************************** + Common functionality needed by many components. + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include +#include +#include +#include +#include +#include "common/utils.hpp" + +#ifndef __infrastructure_HPP +#define __infrastructure_HPP + +#ifndef _MSC_VER // emulate the MSVC-specific sprintf_s using the standard snprintf +#define sprintf_s snprintf //TODO: sprintf_s!=snprintf (http://blog.verg.es/2008/09/sprintfs-is-not-snprintf.html) +#endif + +#ifdef _DEBUG // MSVC Debug build +#define DEBUG // gcc Debug flag +#endif + +/********************************************************/ +/**************** Class Writing Helpers *****************/ +/********************************************************/ +// A macro to disallow any non-defined constructors +// This should be used in the private: declarations for a class +#define DISALLOW_CONSTRUCTION(TypeName) \ + TypeName(); + +// A macro to disallow the copy constructor and operator= functions +// This should be used in the private: declarations for a class +#define DISALLOW_COPY_AND_ASSIGN(TypeName) \ + TypeName(const TypeName&); \ + void operator=(const TypeName&) + +/********************************************************/ +/*************** Debug String Formatting ****************/ +/********************************************************/ + +namespace gadgetlib2 { +// someday, if/when MSVC supports C++0x variadic templates, change FMT in release version to the +// following in order to increase efficiency: +// #define GADGETLIB2_FMT(...) "" +::std::string GADGETLIB2_FMT(const char* format, ...); + +/** Safely converts 64-bit types to 32-bit, or from unsigned to signed */ +long safeConvert(const int64_t num); + +/********************************************************/ +/******************* Error Handling *********************/ +/********************************************************/ + +// declare a function as never returning, to quiet down "control reaches end of non-void function" warnings +#if defined(_MSC_VER) // VisualC++ +#define __noreturn _declspec(noreturn) +#elif defined(__GNUC__) +#define __noreturn __attribute__((noreturn)) +#else +#define __noreturn +#endif + + + + /** + * The ErrorHandling class containimplements the functionality of displaying the content of error + * messages (including content of call stack when error happened), and exiting the program. + */ + class ErrorHandling { + public: + static void __noreturn fatalError(const ::std::string& msg); + static void __noreturn fatalError(const std::stringstream& msg); + static void printStacktrace(); + + }; + +#define GADGETLIB_FATAL(msg) do { \ + ::std::stringstream msgStream; \ + msgStream << msg << " (In file " << __FILE__ << " line " << __LINE__ << ".)"; \ + ErrorHandling::fatalError(msgStream.str()); \ + } while (0) + +// TODO change GADGETLIB_ASSERT to not run in debug +#define GADGETLIB_ASSERT(predicate, msg) if(!(bool(predicate))) GADGETLIB_FATAL(msg); + +/********************************************************/ +/****************** Basic Math **************************/ +/********************************************************/ + +double Log2(double n); + +//Calculates upper bound of Log2 of a number (number of bits needed to represent value) +unsigned int Log2ceil(uint64_t i); + +//Returns true iff the given number is a power of 2. +bool IsPower2(const long x); + + +//Returns a^b when a can be a and b are INTEGERS. +//constexpr int64_t POW(int64_t base, int exponent) { +// return (int64_t) powl((long double)base, (long double)exponent); +//} +//#define POW(a,b) ((int64_t)(pow((float)(a),(int)(b)))) + +// Returns 2^exponent +/*constexpr*/ inline int64_t POW2(int exponent) { + //assert(exponent>=0); + return ((int64_t)1) << exponent; +} + +//Returns the ceiling of a when a is of type double. +/*constexpr*/ inline int64_t CEIL(double a) { + return (int64_t)ceil(a); +} +//#define CEIL(a) ((int64_t)ceil((double)(a))) + +using libsnark::UNUSED; +} // namespace gadgetlib2 + +#endif // __infrastructure_HPP diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib2/integration.cpp b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib2/integration.cpp new file mode 100644 index 0000000..e7c22c4 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib2/integration.cpp @@ -0,0 +1,70 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include "gadgetlib2/adapters.hpp" +#include "gadgetlib2/integration.hpp" + +namespace libsnark { + +linear_combination > convert_gadgetlib2_linear_combination(const gadgetlib2::GadgetLibAdapter::linear_combination_t &lc) +{ + typedef Fr FieldT; + typedef gadgetlib2::GadgetLibAdapter GLA; + + linear_combination result = lc.second * variable(0); + for (const GLA::linear_term_t < : lc.first) + { + result = result + lt.second * variable(lt.first+1); + } + + return result; +} + +r1cs_constraint_system > get_constraint_system_from_gadgetlib2(const gadgetlib2::Protoboard &pb) +{ + typedef Fr FieldT; + typedef gadgetlib2::GadgetLibAdapter GLA; + + r1cs_constraint_system result; + const GLA adapter; + + GLA::protoboard_t converted_pb = adapter.convert(pb); + for (const GLA::constraint_t &constr : converted_pb.first) + { + result.constraints.emplace_back(r1cs_constraint(convert_gadgetlib2_linear_combination(std::get<0>(constr)), + convert_gadgetlib2_linear_combination(std::get<1>(constr)), + convert_gadgetlib2_linear_combination(std::get<2>(constr)))); + } + //The numbers of variables is the highest index created. + //TODO: If there are multiple protoboard, or variables not assigned to a protoboard, then getNextFreeIndex() is *not* the number of variables! See also in get_variable_assignment_from_gadgetlib2. + const size_t num_variables = GLA::getNextFreeIndex(); + result.primary_input_size = pb.numInputs(); + result.auxiliary_input_size = num_variables - pb.numInputs(); + return result; +} + +r1cs_variable_assignment > get_variable_assignment_from_gadgetlib2(const gadgetlib2::Protoboard &pb) +{ + typedef Fr FieldT; + typedef gadgetlib2::GadgetLibAdapter GLA; + + //The numbers of variables is the highest index created. This is also the required size for the assignment vector. + //TODO: If there are multiple protoboard, or variables not assigned to a protoboard, then getNextFreeIndex() is *not* the number of variables! See also in get_constraint_system_from_gadgetlib2. + const size_t num_vars = GLA::getNextFreeIndex(); + const GLA adapter; + r1cs_variable_assignment result(num_vars, FieldT::zero()); + VariableAssignment assignment = pb.assignment(); + + //Go over all assigned values of the protoboard, from every variable-value pair, put the value in the variable.index place of the new assignment. + for(VariableAssignment::iterator iter = assignment.begin(); iter != assignment.end(); ++iter){ + result[GLA::getVariableIndex(iter->first)] = adapter.convert(iter->second); + } + + return result; +} + +} diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib2/integration.hpp b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib2/integration.hpp new file mode 100644 index 0000000..c5dd9e6 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib2/integration.hpp @@ -0,0 +1,22 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef INTEGRATION_HPP_ +#define INTEGRATION_HPP_ + +#include "common/default_types/ec_pp.hpp" +#include "relations/constraint_satisfaction_problems/r1cs/r1cs.hpp" +#include "gadgetlib2/protoboard.hpp" + +namespace libsnark { + +r1cs_constraint_system > get_constraint_system_from_gadgetlib2(const gadgetlib2::Protoboard &pb); +r1cs_variable_assignment > get_variable_assignment_from_gadgetlib2(const gadgetlib2::Protoboard &pb); + +} // libsnark + +#endif // INTEGRATION_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib2/pp.cpp b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib2/pp.cpp new file mode 100644 index 0000000..52d69e1 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib2/pp.cpp @@ -0,0 +1,30 @@ +/** @file + ***************************************************************************** + Implementation of PublicParams for Fp field arithmetic + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include +#include +#include "pp.hpp" + +namespace gadgetlib2 { + +PublicParams::PublicParams(const std::size_t log_p) : log_p(log_p) {} + +Fp PublicParams::getFp(long x) const { + return Fp(x); +} + +PublicParams::~PublicParams() {} + +PublicParams initPublicParamsFromDefaultPp() { + libsnark::default_ec_pp::init_public_params(); + const std::size_t log_p = libsnark::Fr::size_in_bits(); + return PublicParams(log_p); +} + +} // namespace gadgetlib2 diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib2/pp.hpp b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib2/pp.hpp new file mode 100644 index 0000000..046207e --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib2/pp.hpp @@ -0,0 +1,44 @@ +/** @file + ***************************************************************************** + Declaration of PublicParams for Fp field arithmetic + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef LIBSNARK_GADGETLIB2_INCLUDE_GADGETLIB2_PP_HPP_ +#define LIBSNARK_GADGETLIB2_INCLUDE_GADGETLIB2_PP_HPP_ + +#include "common/default_types/ec_pp.hpp" + +#include +#include + +namespace gadgetlib2 { + +/*************************************************************************************************/ +/*************************************************************************************************/ +/******************* ******************/ +/******************* R1P World ******************/ +/******************* ******************/ +/*************************************************************************************************/ +/*************************************************************************************************/ + +/* curve-specific public parameters */ +typedef libsnark::Fr Fp; + +typedef std::vector FpVector; + +class PublicParams { +public: + size_t log_p; + PublicParams(const std::size_t log_p); + Fp getFp(long x) const; // to_support changes later + ~PublicParams(); +}; + +PublicParams initPublicParamsFromDefaultPp(); + +} // namespace gadgetlib2 +#endif // LIBSNARK_GADGETLIB2_INCLUDE_GADGETLIB2_PP_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib2/protoboard.cpp b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib2/protoboard.cpp new file mode 100644 index 0000000..e1d0b33 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib2/protoboard.cpp @@ -0,0 +1,211 @@ +/** @file + ***************************************************************************** + Implementation of Protoboard, a "memory manager" for building arithmetic constraints + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include +#include "protoboard.hpp" + +using ::std::string; +using ::std::cout; +using ::std::endl; + +namespace gadgetlib2 { + +/*************************************************************************************************/ +/*************************************************************************************************/ +/******************* ******************/ +/******************* class Protoboard ******************/ +/******************* ******************/ +/*************************************************************************************************/ +/*************************************************************************************************/ + +Protoboard::Protoboard(const FieldType& fieldType, ParamsCPtr pParams) + : numInputs_(0), pParams_(pParams), fieldType_(fieldType) {} + + +FElem& Protoboard::val(const Variable &var) { + FElem& retval = assignment_[var]; + GADGETLIB_ASSERT(retval.fieldType() == fieldType_ || retval.fieldType() == AGNOSTIC, + GADGETLIB2_FMT("Assigned field element of incorrect field type in Variable \"%s\"", + var.name().c_str())); + return retval; +} + +FElem Protoboard::val(const LinearCombination& lc) const { + return lc.eval(assignment_); +} + +void Protoboard::setValuesAsBitArray(const VariableArray& varArray, const size_t srcValue) { + GADGETLIB_ASSERT(varArray.size() >= Log2ceil(srcValue), + GADGETLIB2_FMT("Variable array of size %u to small to hold value %u. Array must be of size " + "at least %u", varArray.size(), srcValue, Log2ceil(srcValue))); + size_t i = 0; + for(i = 0; i < Log2ceil(srcValue); ++i) { + val(varArray[i]) = srcValue & (1u<>= 1; + } + if (expectedValueCopy != 0) { + retval = false; + } + if (expectedToPrintValues(retval, printOption)) { + cout << "Expected value for unpacked word \"" << unpackedWord.name() + << "\" is: " << expectedValue << endl; + cout << "Actual values are: " << endl; + for(size_t i = 0; i < unpackedWord.size(); ++i) { + cout << "bit " << i << ": " << val(unpackedWord[i]) << endl; + } + } + return retval; +} + + +/***********************************/ +/*** END OF CLASS DEFINITION ***/ +/***********************************/ + +ProtoboardParams::~ProtoboardParams() {} + +} // namespace gadgetlib2 diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib2/protoboard.hpp b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib2/protoboard.hpp new file mode 100644 index 0000000..53aac52 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib2/protoboard.hpp @@ -0,0 +1,119 @@ +/** @file + ***************************************************************************** + Definition of Protoboard, a "memory manager" for building arithmetic constraints + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef LIBSNARK_GADGETLIB2_INCLUDE_GADGETLIB2_PROTOBOARD_HPP_ +#define LIBSNARK_GADGETLIB2_INCLUDE_GADGETLIB2_PROTOBOARD_HPP_ + +#include +#include "pp.hpp" +#include "variable.hpp" +#include "constraint.hpp" + +#define ASSERT_CONSTRAINTS_SATISFIED(pb) \ + ASSERT_TRUE(pb->isSatisfied(PrintOptions::DBG_PRINT_IF_NOT_SATISFIED)) + +#define ASSERT_CONSTRAINTS_NOT_SATISFIED(pb) \ + ASSERT_FALSE(pb->isSatisfied(PrintOptions::NO_DBG_PRINT)) + +namespace gadgetlib2 { + +class ProtoboardParams; // Forward declaration +typedef ::std::shared_ptr ParamsCPtr; + +/*************************************************************************************************/ +/*************************************************************************************************/ +/******************* ******************/ +/******************* class Protoboard ******************/ +/******************* ******************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +class Protoboard { +protected: + VariableAssignment assignment_; + ConstraintSystem constraintSystem_; + size_t numInputs_; + ParamsCPtr pParams_; // TODO try to refactor this out and use inheritance for different types + // of protoboards, for instance TinyRAMProtoboard : public Protoboard + // This may not be trivial because of Gadget multiple inheritance scheme + + Protoboard(const FieldType& fieldType, ParamsCPtr pParams); +public: + const FieldType fieldType_; + static ProtoboardPtr create(const FieldType& fieldType, ParamsCPtr pParams = NULL) { + return ProtoboardPtr(new Protoboard(fieldType, pParams)); + } + size_t numVars() const {return assignment_.size();} // TODO change to take num from constraintSys_ + //size_t numVars() const {return constraintSystem_.getUsedVariables().size();} // TODO change to take num from constraintSys_ + + size_t numInputs() const {return numInputs_;} // TODO Madars How do we book keep this? + ParamsCPtr params() const {return pParams_;} + FElem& val(const Variable& var); + FElem val(const LinearCombination& lc) const; + void setValuesAsBitArray(const VariableArray& varArray, const size_t srcValue); + void setDualWordValue(const DualWord& dualWord, const size_t srcValue); + void setMultipackedWordValue(const MultiPackedWord& multipackedWord, const size_t srcValue); + + // The following 3 methods are purposely not overloaded to the same name in order to reduce + // programmer error. We want the programmer to explicitly code what type of constraint + // she wants. + void addRank1Constraint(const LinearCombination& a, + const LinearCombination& b, + const LinearCombination& c, + const ::std::string& name); + void addGeneralConstraint(const Polynomial& a, + const Polynomial& b, + const ::std::string& name); + /// adds a constraint of the form (a == 0) + void addUnaryConstraint(const LinearCombination& a, const ::std::string& name); + bool isSatisfied(const PrintOptions& printOnFail = PrintOptions::NO_DBG_PRINT); + bool flagIsSet(const FlagVariable& flag) const {return val(flag) == 1;} + void setFlag(const FlagVariable& flag, bool newFlagState = true); + void clearFlag(const FlagVariable& flag) {val(flag) = 0;} + void flipFlag(const FlagVariable& flag) {val(flag) = 1 - val(flag);} + void enforceBooleanity(const Variable& var); + ::std::string annotation() const; + ConstraintSystem constraintSystem() const {return constraintSystem_;} + VariableAssignment assignment() const {return assignment_;} + bool dualWordAssignmentEqualsValue( + const DualWord& dualWord, + const size_t expectedValue, + const PrintOptions& printOption = PrintOptions::NO_DBG_PRINT) const; + bool multipackedWordAssignmentEqualsValue( + const MultiPackedWord& multipackedWord, + const size_t expectedValue, + const PrintOptions& printOption = PrintOptions::NO_DBG_PRINT) const; + bool unpackedWordAssignmentEqualsValue( + const UnpackedWord& unpackedWord, + const size_t expectedValue, + const PrintOptions& printOption = PrintOptions::NO_DBG_PRINT) const; +}; +/***********************************/ +/*** END OF CLASS DEFINITION ***/ +/***********************************/ + +/*************************************************************************************************/ +/*************************************************************************************************/ +/******************* ******************/ +/******************* class ProtoboardParams ******************/ +/******************* ******************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +/* + An abstract class to hold any additional information needed by a specific Protoboard. For + example a Protoboard specific to TinyRAM will have a class ArchParams which will inherit from + this class. +*/ +class ProtoboardParams { +public: + virtual ~ProtoboardParams() = 0; +}; + +} // namespace gadgetlib2 + +#endif // LIBSNARK_GADGETLIB2_INCLUDE_GADGETLIB2_PROTOBOARD_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib2/tests/adapters_UTEST.cpp b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib2/tests/adapters_UTEST.cpp new file mode 100644 index 0000000..dd34df3 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib2/tests/adapters_UTEST.cpp @@ -0,0 +1,105 @@ +/** @file + ***************************************************************************** + Unit tests for gadgetlib2 + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include +#include +#include + +using namespace gadgetlib2; + +namespace { + +TEST(GadgetLibAdapter, LinearTerm) { + initPublicParamsFromDefaultPp(); + const GadgetLibAdapter adapter; + adapter.resetVariableIndex(); + const Variable x("x"); + const LinearTerm lt = 5 * x; + const auto new_lt = adapter.convert(lt); + EXPECT_EQ(new_lt.first, 0u); + EXPECT_EQ(new_lt.second, Fp(5)); +} + +TEST(GadgetLibAdapter, LinearCombination) { + initPublicParamsFromDefaultPp(); + const GadgetLibAdapter adapter; + const Variable x("x"); + const Variable y("y"); + const LinearCombination lc = 5*x + 3*y + 42; + const auto new_lc = adapter.convert(lc); + EXPECT_EQ(new_lc.second, Fp(42)); + EXPECT_EQ(new_lc.first.size(), 2u); + EXPECT_EQ(new_lc.first[0], adapter.convert(5 * x)); + EXPECT_EQ(new_lc.first[1], adapter.convert(3 * y)); +} + +TEST(GadgetLibAdapter, Constraint) { + using ::std::get; + initPublicParamsFromDefaultPp(); + const GadgetLibAdapter adapter; + const Variable x("x"); + const Variable y("y"); + const Rank1Constraint constraint(x + y, 5 * x, 0, "(x + y) * (5 * x) == 0"); + const auto new_constraint = adapter.convert(constraint); + EXPECT_EQ(get<0>(new_constraint), adapter.convert(x + y)); + EXPECT_EQ(get<1>(new_constraint), adapter.convert(5 * x + 0)); + EXPECT_EQ(get<2>(new_constraint), adapter.convert(LinearCombination(0))); +} + +TEST(GadgetLibAdapter, ConstraintSystem) { + initPublicParamsFromDefaultPp(); + const GadgetLibAdapter adapter; + const Variable x("x"); + const Variable y("y"); + const Rank1Constraint constraint0(x + y, 5 * x, 0, "(x + y) * (5*x) == 0"); + const Rank1Constraint constraint1(x, y, 3, "x * y == 3"); + ConstraintSystem system; + system.addConstraint(constraint0); + system.addConstraint(constraint1); + const auto new_constraint_sys = adapter.convert(system); + EXPECT_EQ(new_constraint_sys.size(), 2u); + EXPECT_EQ(new_constraint_sys.at(0), adapter.convert(constraint0)); + EXPECT_EQ(new_constraint_sys.at(1), adapter.convert(constraint1)); +} + +TEST(GadgetLibAdapter, VariableAssignment) { + initPublicParamsFromDefaultPp(); + const GadgetLibAdapter adapter; + adapter.resetVariableIndex(); + const VariableArray varArray(10, "x"); + VariableAssignment assignment; + for (size_t i = 0; i < varArray.size(); ++i) { + assignment[varArray[i]] = i; + } + const auto new_assignment = adapter.convert(assignment); + ASSERT_EQ(assignment.size(), new_assignment.size()); + for (size_t i = 0; i < new_assignment.size(); ++i) { + const GadgetLibAdapter::variable_index_t var = i; + EXPECT_EQ(new_assignment.at(var), Fp(i)); + } +} + +TEST(GadgetLibAdapter, Protoboard) { + initPublicParamsFromDefaultPp(); + const GadgetLibAdapter adapter; + adapter.resetVariableIndex(); + const Variable x("x"); + const Variable y("y"); + ProtoboardPtr pb = Protoboard::create(R1P); + pb->addRank1Constraint(x + y, 5 * x, 0, "(x + y) * (5*x) == 0"); + pb->addRank1Constraint(x, y, 3, "x * y == 3"); + pb->val(x) = 1; + pb->val(y) = 2; + const auto new_pb = adapter.convert(*pb); + EXPECT_EQ(new_pb.first, adapter.convert(pb->constraintSystem())); + EXPECT_EQ(new_pb.second, adapter.convert(pb->assignment())); +} + + +} // namespace diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib2/tests/constraint_UTEST.cpp b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib2/tests/constraint_UTEST.cpp new file mode 100644 index 0000000..8daf2e5 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib2/tests/constraint_UTEST.cpp @@ -0,0 +1,50 @@ +/** @file + ***************************************************************************** + Unit tests for gadgetlib2 - test rank + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include +#include +#include +#include + +using ::std::set; +using namespace gadgetlib2; + +namespace { + +TEST(gadgetLib2, Rank1Constraint) { + initPublicParamsFromDefaultPp(); + VariableArray x(10,"x"); + VariableAssignment assignment; + for(int i = 0; i < 10; ++i) { + assignment[x[i]] = Fp(i); + } + LinearCombination a = x[0] + x[1] + 2; // = 0+1+2=3 + LinearCombination b = 2*x[2] - 3*x[3] + 4; // = 2*2-3*3+4=-1 + LinearCombination c = x[5]; // = 5 + Rank1Constraint c1(a,b,c,"c1"); + EXPECT_EQ(c1.a().eval(assignment), a.eval(assignment)); + EXPECT_EQ(c1.b().eval(assignment), b.eval(assignment)); + EXPECT_EQ(c1.c().eval(assignment), c.eval(assignment)); + EXPECT_FALSE(c1.isSatisfied(assignment)); + EXPECT_FALSE(c1.isSatisfied(assignment, PrintOptions::NO_DBG_PRINT)); + assignment[x[5]] = -3; + EXPECT_TRUE(c1.isSatisfied(assignment)); + EXPECT_TRUE(c1.isSatisfied(assignment, PrintOptions::NO_DBG_PRINT)); + const Variable::set varSet = c1.getUsedVariables(); + EXPECT_EQ(varSet.size(), 5u); + EXPECT_TRUE(varSet.find(x[0]) != varSet.end()); + EXPECT_TRUE(varSet.find(x[1]) != varSet.end()); + EXPECT_TRUE(varSet.find(x[2]) != varSet.end()); + EXPECT_TRUE(varSet.find(x[3]) != varSet.end()); + EXPECT_TRUE(varSet.find(x[4]) == varSet.end()); + EXPECT_TRUE(varSet.find(x[5]) != varSet.end()); +} + + +} // namespace diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib2/tests/gadget_UTEST.cpp b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib2/tests/gadget_UTEST.cpp new file mode 100644 index 0000000..44aaf01 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib2/tests/gadget_UTEST.cpp @@ -0,0 +1,409 @@ +/** @file + ***************************************************************************** + Unit tests for gadgetlib2 - tests for specific gadgets + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include +#include +#include +#include +#include +#include + +using ::std::cerr; +using ::std::cout; +using ::std::endl; +using ::std::stringstream; +using namespace gadgetlib2; + +#define EXHAUSTIVE_N 4 + +namespace { + +TEST(gadgetLib2,R1P_AND_Gadget_SimpleTest) { + initPublicParamsFromDefaultPp(); + auto pb = Protoboard::create(R1P); + + VariableArray x(3, "x"); + Variable y("y"); + auto andGadget = AND_Gadget::create(pb, x, y); + andGadget->generateConstraints(); + + pb->val(x[0]) = 0; + pb->val(x[1]) = 1; + pb->val(x[2]) = 1; + andGadget->generateWitness(); + EXPECT_TRUE(pb->val(y) == 0); + EXPECT_TRUE(pb->isSatisfied(PrintOptions::DBG_PRINT_IF_NOT_SATISFIED)); + pb->val(y) = 1; + EXPECT_FALSE(pb->isSatisfied()); + + pb->val(x[0]) = 1; + andGadget->generateWitness(); + EXPECT_TRUE(pb->val(y) == 1); + EXPECT_TRUE(pb->isSatisfied(PrintOptions::DBG_PRINT_IF_NOT_SATISFIED)); + + pb->val(y) = 0; + EXPECT_FALSE(pb->isSatisfied()); +} + +class LogicGadgetExhaustiveTester { +protected: + ProtoboardPtr pb; + const size_t numInputs; + const VariableArray inputs; + const Variable output; + GadgetPtr logicGadget; + size_t currentInputValues; + + LogicGadgetExhaustiveTester(ProtoboardPtr pb, size_t numInputs); + void setInputValsTo(const size_t val); + void runCompletenessCheck(); + virtual void ruinOutputVal() = 0; + void runSoundnessCheck(); + + DISALLOW_COPY_AND_ASSIGN(LogicGadgetExhaustiveTester); +public: + void runExhaustiveTest(); +}; + +class AndGadgetExhaustiveTester : public LogicGadgetExhaustiveTester { +private: virtual void ruinOutputVal(); +public: AndGadgetExhaustiveTester(ProtoboardPtr pb, size_t numInputs); +}; + +class OrGadgetExhaustiveTester : public LogicGadgetExhaustiveTester { +private: virtual void ruinOutputVal(); +public: OrGadgetExhaustiveTester(ProtoboardPtr pb, size_t numInputs); +}; + + +TEST(gadgetLib2,R1P_ANDGadget_ExhaustiveTest) { + initPublicParamsFromDefaultPp(); + for(int inputSize = 1; inputSize <= EXHAUSTIVE_N; ++inputSize) { + SCOPED_TRACE(GADGETLIB2_FMT("n = %u \n", inputSize)); + auto pb = Protoboard::create(R1P); + AndGadgetExhaustiveTester tester(pb, inputSize); + tester.runExhaustiveTest(); + } +} + +TEST(gadgetLib2,BinaryAND_Gadget) { + auto pb = Protoboard::create(R1P); + Variable input1("input1"); + Variable input2("input2"); + Variable result("result"); + auto andGadget = AND_Gadget::create(pb, input1, input2, result); + andGadget->generateConstraints(); + pb->val(input1) = pb->val(input2) = 0; + andGadget->generateWitness(); + ASSERT_TRUE(pb->isSatisfied(PrintOptions::DBG_PRINT_IF_NOT_SATISFIED)); + ASSERT_EQ(pb->val(result), 0); + pb->val(result) = 1; + ASSERT_FALSE(pb->isSatisfied()); + pb->val(result) = 0; + pb->val(input1) = 1; + ASSERT_TRUE(pb->isSatisfied(PrintOptions::DBG_PRINT_IF_NOT_SATISFIED)); + pb->val(input2) = 1; + ASSERT_FALSE(pb->isSatisfied()); + andGadget->generateWitness(); + ASSERT_TRUE(pb->isSatisfied(PrintOptions::DBG_PRINT_IF_NOT_SATISFIED)); + ASSERT_EQ(pb->val(result), 1); +} + +TEST(gadgetLib2,R1P_ORGadget_Exhaustive) { + initPublicParamsFromDefaultPp(); + for(int n = 1; n <= EXHAUSTIVE_N; ++n) { + SCOPED_TRACE(GADGETLIB2_FMT("n = %u \n", n)); + auto pb = Protoboard::create(R1P); + OrGadgetExhaustiveTester tester(pb, n); + tester.runExhaustiveTest(); + } +} + +TEST(gadgetLib2,BinaryOR_Gadget) { + auto pb = Protoboard::create(R1P); + Variable input1("input1"); + Variable input2("input2"); + Variable result("result"); + auto orGadget = OR_Gadget::create(pb, input1, input2, result); + orGadget->generateConstraints(); + pb->val(input1) = pb->val(input2) = 0; + orGadget->generateWitness(); + ASSERT_TRUE(pb->isSatisfied(PrintOptions::DBG_PRINT_IF_NOT_SATISFIED)); + ASSERT_EQ(pb->val(result), 0); + pb->val(result) = 1; + ASSERT_FALSE(pb->isSatisfied()); + pb->val(result) = 0; + pb->val(input1) = 1; + ASSERT_FALSE(pb->isSatisfied()); + pb->val(result) = 1; + ASSERT_CONSTRAINTS_SATISFIED(pb); + pb->val(input2) = 1; + orGadget->generateWitness(); + ASSERT_TRUE(pb->isSatisfied(PrintOptions::DBG_PRINT_IF_NOT_SATISFIED)); + ASSERT_EQ(pb->val(result), 1); +} + +// TODO refactor this test --Shaul +TEST(gadgetLib2,R1P_InnerProductGadget_Exhaustive) { + initPublicParamsFromDefaultPp(); + const size_t n = EXHAUSTIVE_N; + auto pb = Protoboard::create(R1P); + VariableArray A(n, "A"); + VariableArray B(n, "B"); + Variable result("result"); + auto g = InnerProduct_Gadget::create(pb, A, B, result); + g->generateConstraints(); + for (size_t i = 0; i < 1u<val(A[k]) = i & (1u<val(B[k]) = j & (1u<generateWitness(); + EXPECT_EQ(pb->val(result) , FElem(correct)); + EXPECT_TRUE(pb->isSatisfied()); + // negative test + pb->val(result) = 100*n+19; + EXPECT_FALSE(pb->isSatisfied()); + } + } +} + +// TODO refactor this test --Shaul +TEST(gadgetLib2,R1P_LooseMUX_Gadget_Exhaustive) { +initPublicParamsFromDefaultPp(); +const size_t n = EXHAUSTIVE_N; + auto pb = Protoboard::create(R1P); + VariableArray arr(1<generateConstraints(); + for (size_t i = 0; i < 1u<val(arr[i]) = (19*i) % (1u<val(index) = idx; + g->generateWitness(); + if (0 <= idx && idx <= (1<val(result) , (19*idx) % (1u<val(success_flag) , 1); + EXPECT_TRUE(pb->isSatisfied(PrintOptions::DBG_PRINT_IF_NOT_SATISFIED)); + pb->val(result) -= 1; + EXPECT_FALSE(pb->isSatisfied()); + } + else { + EXPECT_EQ(pb->val(success_flag) , 0); + EXPECT_TRUE(pb->isSatisfied(PrintOptions::DBG_PRINT_IF_NOT_SATISFIED)); + pb->val(success_flag) = 1; + EXPECT_FALSE(pb->isSatisfied()); + } + } +} + +// Forward declaration +void packing_Gadget_R1P_ExhaustiveTest(ProtoboardPtr unpackingPB, ProtoboardPtr packingPB, + const int n, VariableArray packed, VariableArray unpacked, + GadgetPtr packingGadget, GadgetPtr unpackingGadget); + +// TODO refactor this test --Shaul +TEST(gadgetLib2,R1P_Packing_Gadgets) { + initPublicParamsFromDefaultPp(); + auto unpackingPB = Protoboard::create(R1P); + auto packingPB = Protoboard::create(R1P); + const int n = EXHAUSTIVE_N; + { // test CompressionPacking_Gadget + SCOPED_TRACE("testing CompressionPacking_Gadget"); + VariableArray packed(1, "packed"); + VariableArray unpacked(n, "unpacked"); + auto packingGadget = CompressionPacking_Gadget::create(packingPB, unpacked, packed, + PackingMode::PACK); + auto unpackingGadget = CompressionPacking_Gadget::create(unpackingPB, unpacked, packed, + PackingMode::UNPACK); + packing_Gadget_R1P_ExhaustiveTest(unpackingPB, packingPB, n, packed, unpacked, packingGadget, + unpackingGadget); + } + { // test IntegerPacking_Gadget + SCOPED_TRACE("testing IntegerPacking_Gadget"); + VariableArray packed(1, "packed"); + VariableArray unpacked(n, "unpacked"); + auto packingGadget = IntegerPacking_Gadget::create(packingPB, unpacked, packed, + PackingMode::PACK); + auto unpackingGadget = IntegerPacking_Gadget::create(unpackingPB, unpacked, packed, + PackingMode::UNPACK); + packing_Gadget_R1P_ExhaustiveTest(unpackingPB, packingPB, n, packed, unpacked, packingGadget, + unpackingGadget); + } +} + +TEST(gadgetLib2,R1P_EqualsConst_Gadget) { + initPublicParamsFromDefaultPp(); + auto pb = Protoboard::create(R1P); + Variable input("input"); + Variable result("result"); + auto gadget = EqualsConst_Gadget::create(pb, 0, input, result); + gadget->generateConstraints(); + pb->val(input) = 0; + gadget->generateWitness(); + // Positive test for input == n + EXPECT_EQ(pb->val(result), 1); + EXPECT_TRUE(pb->isSatisfied()); + // Negative test + pb->val(result) = 0; + EXPECT_FALSE(pb->isSatisfied()); + // Positive test for input != n + pb->val(input) = 1; + gadget->generateWitness(); + EXPECT_EQ(pb->val(result), 0); + EXPECT_TRUE(pb->isSatisfied()); + // Negative test + pb->val(input) = 0; + EXPECT_FALSE(pb->isSatisfied()); +} + +TEST(gadgetLib2,ConditionalFlag_Gadget) { + initPublicParamsFromDefaultPp(); + auto pb = Protoboard::create(R1P); + FlagVariable flag; + Variable condition("condition"); + auto cfGadget = ConditionalFlag_Gadget::create(pb, condition, flag); + cfGadget->generateConstraints(); + pb->val(condition) = 1; + cfGadget->generateWitness(); + ASSERT_TRUE(pb->isSatisfied(PrintOptions::DBG_PRINT_IF_NOT_SATISFIED)); + pb->val(condition) = 42; + cfGadget->generateWitness(); + ASSERT_TRUE(pb->isSatisfied(PrintOptions::DBG_PRINT_IF_NOT_SATISFIED)); + ASSERT_EQ(pb->val(flag),1); + pb->val(condition) = 0; + ASSERT_FALSE(pb->isSatisfied()); + cfGadget->generateWitness(); + ASSERT_TRUE(pb->isSatisfied(PrintOptions::DBG_PRINT_IF_NOT_SATISFIED)); + ASSERT_EQ(pb->val(flag),0); + pb->val(flag) = 1; + ASSERT_FALSE(pb->isSatisfied()); +} + +TEST(gadgetLib2,LogicImplication_Gadget) { + auto pb = Protoboard::create(R1P); + FlagVariable flag; + Variable condition("condition"); + auto implyGadget = LogicImplication_Gadget::create(pb, condition, flag); + implyGadget->generateConstraints(); + pb->val(condition) = 1; + pb->val(flag) = 0; + ASSERT_FALSE(pb->isSatisfied()); + implyGadget->generateWitness(); + ASSERT_TRUE(pb->isSatisfied(PrintOptions::DBG_PRINT_IF_NOT_SATISFIED)); + ASSERT_EQ(pb->val(flag), 1); + pb->val(condition) = 0; + ASSERT_TRUE(pb->isSatisfied(PrintOptions::DBG_PRINT_IF_NOT_SATISFIED)); + implyGadget->generateWitness(); + ASSERT_EQ(pb->val(flag), 1); + pb->val(flag) = 0; + ASSERT_TRUE(pb->isSatisfied(PrintOptions::DBG_PRINT_IF_NOT_SATISFIED)); +} + +// TODO refactor this test --Shaul +void packing_Gadget_R1P_ExhaustiveTest(ProtoboardPtr unpackingPB, ProtoboardPtr packingPB, + const int n, VariableArray packed, VariableArray unpacked, + GadgetPtr packingGadget, GadgetPtr unpackingGadget) { + packingGadget->generateConstraints(); + unpackingGadget->generateConstraints(); + for(int i = 0; i < 1l< bits(n); + for(int j = 0; j < n; ++j) { + bits[j] = i & 1u<val(unpacked[j]) = bits[j]; // set unpacked bits in the packing protoboard + } + unpackingPB->val(packed[0]) = i; // set the packed value in the unpacking protoboard + unpackingGadget->generateWitness(); + packingGadget->generateWitness(); + ASSERT_TRUE(unpackingPB->isSatisfied(PrintOptions::DBG_PRINT_IF_NOT_SATISFIED)); + ASSERT_TRUE(packingPB->isSatisfied()); + ASSERT_EQ(packingPB->val(packed[0]), i); // check packed value is correct + for(int j = 0; j < n; ++j) { + // Tests for unpacking gadget + SCOPED_TRACE(GADGETLIB2_FMT("\nValue being packed/unpacked: %u, bits[%u] = %u" , i, j, bits[j])); + ASSERT_EQ(unpackingPB->val(unpacked[j]), bits[j]); // check bit correctness + packingPB->val(unpacked[j]) = unpackingPB->val(unpacked[j]) = 1-bits[j]; // flip bit + ASSERT_FALSE(unpackingPB->isSatisfied()); + ASSERT_FALSE(packingPB->isSatisfied()); + packingPB->val(unpacked[j]) = unpackingPB->val(unpacked[j]) = bits[j]; // restore bit + // special case to test booleanity checks. Cause arithmetic constraints to stay + // satisfied while ruining Booleanity + if (j > 0 && bits[j]==1 && bits[j-1]==0 ) { + packingPB->val(unpacked[j-1]) = unpackingPB->val(unpacked[j-1]) = 2; + packingPB->val(unpacked[j]) = unpackingPB->val(unpacked[j]) = 0; + ASSERT_FALSE(unpackingPB->isSatisfied()); + ASSERT_TRUE(packingPB->isSatisfied()); // packing should not enforce Booleanity + // restore correct state + packingPB->val(unpacked[j-1]) = unpackingPB->val(unpacked[j-1]) = 0; + packingPB->val(unpacked[j]) = unpackingPB->val(unpacked[j]) = 1; + } + } + } +} + + +void LogicGadgetExhaustiveTester::setInputValsTo(const size_t val) { + for (size_t maskBit = 0; maskBit < numInputs; ++maskBit) { + pb->val(inputs[maskBit]) = (val & (1u << maskBit)) ? 1 : 0; + } +} + +void LogicGadgetExhaustiveTester::runCompletenessCheck() { + SCOPED_TRACE(GADGETLIB2_FMT("Positive (completeness) test failed. curInput: %u", currentInputValues)); + EXPECT_TRUE(pb->isSatisfied()); +} + +void LogicGadgetExhaustiveTester::runSoundnessCheck() { + SCOPED_TRACE(pb->annotation()); + SCOPED_TRACE(GADGETLIB2_FMT("Negative (soundness) test failed. curInput: %u, Constraints " + "are:", currentInputValues)); + EXPECT_FALSE(pb->isSatisfied()); +} +LogicGadgetExhaustiveTester::LogicGadgetExhaustiveTester(ProtoboardPtr pb, size_t numInputs) + : pb(pb), numInputs(numInputs), inputs(numInputs, "inputs"), output("output"), + currentInputValues(0) {} + +void LogicGadgetExhaustiveTester::runExhaustiveTest() { + logicGadget->generateConstraints(); + for (currentInputValues = 0; currentInputValues < (1u << numInputs); ++currentInputValues) { + setInputValsTo(currentInputValues); + logicGadget->generateWitness(); + runCompletenessCheck(); + ruinOutputVal(); + runSoundnessCheck(); + } +} + +void AndGadgetExhaustiveTester::ruinOutputVal() { + pb->val(output) = (currentInputValues == ((1u << numInputs) - 1)) ? 0 : 1; +} + +AndGadgetExhaustiveTester::AndGadgetExhaustiveTester(ProtoboardPtr pb, size_t numInputs) + : LogicGadgetExhaustiveTester(pb, numInputs) { + logicGadget = AND_Gadget::create(pb, inputs, output); +} + +void OrGadgetExhaustiveTester::ruinOutputVal() { + pb->val(output) = (currentInputValues == 0) ? 1 : 0; +} + +OrGadgetExhaustiveTester::OrGadgetExhaustiveTester(ProtoboardPtr pb, size_t numInputs) + : LogicGadgetExhaustiveTester(pb, numInputs) { + logicGadget = OR_Gadget::create(pb, inputs, output); +} + + +} // namespace diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib2/tests/gadgetlib2_test.cpp b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib2/tests/gadgetlib2_test.cpp new file mode 100644 index 0000000..a625592 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib2/tests/gadgetlib2_test.cpp @@ -0,0 +1,15 @@ +/** @file + ***************************************************************************** + Unit tests for gadgetlib2 - main() for running all tests + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include + +int main(int argc, char **argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} \ No newline at end of file diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib2/tests/integration_UTEST.cpp b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib2/tests/integration_UTEST.cpp new file mode 100644 index 0000000..abe7b2f --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib2/tests/integration_UTEST.cpp @@ -0,0 +1,35 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include +#include +#include +#include +#include +#include + +#include "common/default_types/r1cs_ppzksnark_pp.hpp" +#include "relations/constraint_satisfaction_problems/r1cs/examples/r1cs_examples.hpp" +#include "gadgetlib2/examples/simple_example.hpp" +#include "zk_proof_systems/ppzksnark/r1cs_ppzksnark/examples/run_r1cs_ppzksnark.hpp" + +using namespace gadgetlib2; + +namespace { + +TEST(gadgetLib2,Integration) { + using namespace libsnark; + + initPublicParamsFromDefaultPp(); + const r1cs_example > example = gen_r1cs_example_from_gadgetlib2_protoboard(100); + const bool test_serialization = false; + + const bool bit = run_r1cs_ppzksnark(example, test_serialization); + EXPECT_TRUE(bit); +}; + +} diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib2/tests/protoboard_UTEST.cpp b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib2/tests/protoboard_UTEST.cpp new file mode 100644 index 0000000..3cad068 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib2/tests/protoboard_UTEST.cpp @@ -0,0 +1,63 @@ +/** @file + ***************************************************************************** + Unit tests for gadgetlib2 protoboard + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include +#include +#include + +using namespace gadgetlib2; + +namespace { + +TEST(gadgetLib2,R1P_enforceBooleanity) { + initPublicParamsFromDefaultPp(); + auto pb = Protoboard::create(R1P); + Variable x; + pb->enforceBooleanity(x); + pb->val(x) = 0; + EXPECT_TRUE(pb->isSatisfied(PrintOptions::DBG_PRINT_IF_NOT_SATISFIED)); + pb->val(x) = 1; + EXPECT_TRUE(pb->isSatisfied(PrintOptions::DBG_PRINT_IF_NOT_SATISFIED)); + pb->val(x) = Fp(2); + EXPECT_FALSE(pb->isSatisfied()); +} + +TEST(gadgetLib2, Protoboard_unpackedWordAssignmentEqualsValue_R1P) { + initPublicParamsFromDefaultPp(); + auto pb = Protoboard::create(R1P); + const UnpackedWord unpacked(8, "unpacked"); + pb->setValuesAsBitArray(unpacked, 42); + ASSERT_TRUE(pb->unpackedWordAssignmentEqualsValue(unpacked, 42)); + ASSERT_FALSE(pb->unpackedWordAssignmentEqualsValue(unpacked, 43)); + ASSERT_FALSE(pb->unpackedWordAssignmentEqualsValue(unpacked, 1024 + 42)); +} + +TEST(gadgetLib2, Protoboard_multipackedWordAssignmentEqualsValue_R1P) { + initPublicParamsFromDefaultPp(); + auto pb = Protoboard::create(R1P); + const MultiPackedWord multipacked(8, R1P, "multipacked"); + pb->val(multipacked[0]) = 42; + ASSERT_TRUE(pb->multipackedWordAssignmentEqualsValue(multipacked, 42)); + ASSERT_FALSE(pb->multipackedWordAssignmentEqualsValue(multipacked, 43)); + const MultiPackedWord multipackedAgnostic(AGNOSTIC); + ASSERT_THROW(pb->multipackedWordAssignmentEqualsValue(multipackedAgnostic, 43), + ::std::runtime_error); +} + +TEST(gadgetLib2, Protoboard_dualWordAssignmentEqualsValue_R1P) { + initPublicParamsFromDefaultPp(); + auto pb = Protoboard::create(R1P); + const DualWord dualword(8, R1P, "dualword"); + pb->setDualWordValue(dualword, 42); + ASSERT_TRUE(pb->dualWordAssignmentEqualsValue(dualword, 42)); + ASSERT_FALSE(pb->dualWordAssignmentEqualsValue(dualword, 43)); + ASSERT_FALSE(pb->dualWordAssignmentEqualsValue(dualword, 42 + 1024)); +} + +} // namespace diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib2/tests/variable_UTEST.cpp b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib2/tests/variable_UTEST.cpp new file mode 100644 index 0000000..b70fded --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib2/tests/variable_UTEST.cpp @@ -0,0 +1,701 @@ +/** @file + ***************************************************************************** + Unit tests for gadgetlib2 variables + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include +#include +#include +#include + +using ::std::set; +using namespace gadgetlib2; + +namespace { + +TEST(gadgetLib2, VariableNaming) { + Variable v1; + EXPECT_EQ(v1.name(), ""); + Variable v2("foo"); +# ifdef DEBUG + EXPECT_EQ(v2.name(), "foo"); +# endif + v2 = v1; + EXPECT_EQ(v2.name(), ""); +} + +TEST(gadgetLib2, VariableStrictOrdering) { + Variable v1; + Variable v2; + Variable::VariableStrictOrder orderFunc; + EXPECT_TRUE(orderFunc(v1, v2) || orderFunc(v2, v1)); // check strict ordering + v2 = v1; + EXPECT_FALSE(orderFunc(v1, v2) || orderFunc(v2, v1)); +} + + +TEST(gadgetLib2, VariableSet) { + Variable v1; + Variable::set s1; + s1.insert(v1); + EXPECT_EQ(s1.size(), 1u); + Variable v2; + v2 = v1; + s1.insert(v2); + EXPECT_EQ(s1.size(), 1u); + Variable v3; + s1.insert(v3); + EXPECT_EQ(s1.size(), 2u); + Variable v4; + s1.erase(v4); + EXPECT_EQ(s1.size(), 2u); + v4 = v1; + s1.erase(v4); + EXPECT_EQ(s1.size(), 1u); +} + +TEST(gadgetLib2, VariableArray) { + Variable v1; + Variable v2("v2"); + VariableArray vArr; + vArr.push_back(v1); + vArr.push_back(v2); + EXPECT_EQ(vArr.size(),2u); + Variable::VariableStrictOrder orderFunc; + EXPECT_TRUE(orderFunc(vArr[0],vArr[1]) || orderFunc(vArr[1],vArr[0])); // check strict ordering + vArr[1] = vArr[0]; + EXPECT_FALSE(orderFunc(vArr[0],vArr[1]) || orderFunc(vArr[1],vArr[0])); // check strict ordering + EXPECT_THROW(vArr.at(2) = v1, ::std::out_of_range); +} + +TEST(gadgetLib2, VariableEval) { + initPublicParamsFromDefaultPp(); + VariableArray x(10, "x"); + VariableAssignment ass; + ass[x[0]] = Fp(42); + EXPECT_EQ(x[0].eval(ass), 42); + EXPECT_NE(x[0].eval(ass), 17); +} + +TEST(gadgetLib2, FElem_FConst_fromLong) { + initPublicParamsFromDefaultPp(); + FElem e0(long(0)); + EXPECT_TRUE(e0 == 0); +} + +TEST(gadgetLib2, FElem_FConst_fromInt) { + initPublicParamsFromDefaultPp(); + FElem e1(int(1)); + EXPECT_TRUE(e1 == 1); + FElem e2(2); + EXPECT_EQ(e2, FElem(2)); +} + +TEST(gadgetLib2, FElem_FConst_copy) { + initPublicParamsFromDefaultPp(); + FElem e0(long(0)); + FElem e1(int(1)); + FElem e3(e1); + EXPECT_TRUE(e3 == 1); + e3 = 0; + EXPECT_TRUE(e3 == 0); + ASSERT_EQ(e1, 1); + e0 = e1; + EXPECT_EQ(e0, e1); + e0 = 0; + EXPECT_NE(e0, e1); +} + +TEST(gadgetLib2, FElem_FConst_move) { + initPublicParamsFromDefaultPp(); + FElem e4(FElem(4)); + EXPECT_EQ(e4, FElem(4)); +} + +TEST(gadgetLib2, FElem_FConst_assignment) { + initPublicParamsFromDefaultPp(); + FElem e0(0); + FElem e1(0); + e0 = e1 = 42; + EXPECT_EQ(e1, FElem(42)); + EXPECT_EQ(e0, e1); +} + +TEST(gadgetLib2, FElem_FConst_asString) { + initPublicParamsFromDefaultPp(); + FElem e0(42); + #ifdef DEBUG + EXPECT_EQ(e0.asString(), "42"); + #else + EXPECT_EQ(e0.asString(), ""); + #endif +} + +TEST(gadgetLib2, FElem_FConst_fieldType) { + initPublicParamsFromDefaultPp(); + FElem e0(42); + EXPECT_EQ(e0.fieldType(), AGNOSTIC); + e0 = Fp(42); + EXPECT_NE(e0.fieldType(), AGNOSTIC); +} + +TEST(gadgetLib2, FElem_FConst_operatorEquals) { + initPublicParamsFromDefaultPp(); + FElem e0(long(0)); + FElem e1(int(1)); + FElem e2(FElem(2)); + e0 = e1 = 42; + //bool operator==(const FElem& other) const {return *elem_ == *other.elem_;} + EXPECT_TRUE(e1 == e0); + EXPECT_FALSE(e1 == e2); + FElem eR1P = Fp(42); + EXPECT_TRUE(e1 == eR1P); + EXPECT_TRUE(eR1P == e1); + //bool operator==(const FElem& first, const long second); + FElem e3(FElem(4)); + EXPECT_TRUE(e3 == 4); + //bool operator==(const long first, const FElem& second); + EXPECT_TRUE(4 == e3); +} + +TEST(gadgetLib2, FElem_FConst_operatorPlus) { + initPublicParamsFromDefaultPp(); + //FElem& operator+=(const FElem& other) {*elem_ += *other.elem_; return *this;} + FElem e0(0); + FElem e1(0); + e0 = e1 = 42; + e1 = e0 += e1; + EXPECT_EQ(e0, FElem(84)); + EXPECT_TRUE(e1 == 84); +} + +TEST(gadgetLib2, FElem_FConst_operatorMinus) { + initPublicParamsFromDefaultPp(); + //FElem& operator+=(const FElem& other) {*elem_ += *other.elem_; return *this;} + FElem e0(0); + FElem e1(0); + e0 = e1 = 42; + e1 = e0 -= e1; + EXPECT_TRUE(e0 == 0); + EXPECT_TRUE(e1 == 0); + e0 = 21; + e1 = 2; + EXPECT_EQ(e0, FElem(21)); + EXPECT_TRUE(e1 == 2); +} + +TEST(gadgetLib2, FElem_FConst_operatorTimes) { + initPublicParamsFromDefaultPp(); + //FElem& operator+=(const FElem& other) {*elem_ += *other.elem_; return *this;} + FElem e0 = 21; + FElem e1 = 2; + e1 = e0 *= e1; + EXPECT_TRUE(e0 == 42); + EXPECT_TRUE(e1 == 42); + EXPECT_TRUE(e0 == e1); + EXPECT_TRUE(e0 == 42); + EXPECT_TRUE(42 == e0); +} + +TEST(gadgetLib2, FElem_FConst_operatorUnaryMinus) { + initPublicParamsFromDefaultPp(); + FElem e4(FElem(4)); + EXPECT_EQ(-e4, FElem(-4)); +} + +TEST(gadgetLib2, FElem_FConst_operatorNotEquals) { + initPublicParamsFromDefaultPp(); + FElem e0 = 21; + FElem e4(FElem(4)); + //bool operator!=(const FElem& first, const FElem& second); + EXPECT_TRUE(e4 != e0); + //bool operator!=(const FElem& first, const long second); + EXPECT_TRUE(e4 != 5); + //bool operator!=(const long first, const FElem& second); + EXPECT_TRUE(5 != e4); +} + +TEST(gadgetLib2, FElem_FConst_inverse) { + initPublicParamsFromDefaultPp(); + FElem e4 = 4; + FElem eInv = e4.inverse(R1P); + EXPECT_EQ(eInv, FElem(Fp(e4.asLong()).inverse())); +} + + +TEST(gadgetLib2, FElem_R1P_Elem_constructor) { + initPublicParamsFromDefaultPp(); + FElem e0(Fp(0)); + EXPECT_EQ(e0, 0); + EXPECT_NE(e0, 1); +} + +TEST(gadgetLib2, FElem_R1P_Elem_copy) { + initPublicParamsFromDefaultPp(); + FElem e0(Fp(0)); + FElem e1(e0); + EXPECT_EQ(e1, 0); +} + +TEST(gadgetLib2, FElem_R1P_Elem_assignment) { + initPublicParamsFromDefaultPp(); + initPublicParamsFromDefaultPp(); + FElem e0(Fp(0)); + FElem e1(e0); + FElem e2 = Fp(2); + e1 = e2; + EXPECT_EQ(e1, 2); + FElem e3 = 3; + e1 = e3; + EXPECT_EQ(e1, 3); +} + +TEST(gadgetLib2, FElem_R1P_Elem_move) { + initPublicParamsFromDefaultPp(); + FElem e1 = 1; + e1 = FElem(Fp(2)); + EXPECT_EQ(e1, 2); + e1 = FElem(1); + EXPECT_EQ(e1, 1); +} + +TEST(gadgetLib2, FElem_R1P_Elem_assignFromLong) { + initPublicParamsFromDefaultPp(); + FElem e1 = FElem(1); + e1 = long(42); + EXPECT_EQ(e1, 42); +} + +TEST(gadgetLib2, FElem_R1P_Elem_asString) { + initPublicParamsFromDefaultPp(); + FElem e1 = long(42); + #ifdef DEBUG + EXPECT_EQ(e1.asString(), "42"); + #else + EXPECT_EQ(e1.asString(), ""); + #endif +} + +TEST(gadgetLib2, FElem_R1P_Elem_fieldType) { + initPublicParamsFromDefaultPp(); + FElem e1 = Fp(42); + EXPECT_EQ(e1.fieldType(), R1P); +} + +TEST(gadgetLib2, FElem_R1P_Elem_operatorEquals) { + initPublicParamsFromDefaultPp(); + FElem e0 = 42; + FElem e1 = long(42); + FElem e2 = Fp(2); + EXPECT_TRUE(e0 == e1); + EXPECT_FALSE(e0 == e2); + EXPECT_FALSE(e0 != e1); + EXPECT_TRUE(e0 == 42); + EXPECT_FALSE(e0 == 41); + EXPECT_TRUE(e0 != 41); + EXPECT_TRUE(42 == e0); + EXPECT_TRUE(41 != e0); +} + +TEST(gadgetLib2, FElem_R1P_Elem_negativeNums) { + initPublicParamsFromDefaultPp(); + FElem e1 = long(42); + FElem e2 = Fp(2); + FElem e0 = e1 = -42; + EXPECT_TRUE(e0 == e1); + EXPECT_FALSE(e0 == e2); + EXPECT_FALSE(e0 != e1); + EXPECT_TRUE(e0 == -42); + EXPECT_FALSE(e0 == -41); + EXPECT_TRUE(e0 != -41); + EXPECT_TRUE(-42 == e0); + EXPECT_TRUE(-41 != e0); +} + +TEST(gadgetLib2, FElem_R1P_Elem_operatorTimes) { + initPublicParamsFromDefaultPp(); + FElem e1 = Fp(1); + FElem e2 = Fp(2); + FElem e3 = Fp(3); + EXPECT_TRUE(e1.fieldType() == R1P && e2.fieldType() == R1P); + e1 = e2 *= e3; + EXPECT_EQ(e1, 6); + EXPECT_EQ(e2, 6); + EXPECT_EQ(e3, 3); +} + +TEST(gadgetLib2, FElem_R1P_Elem_operatorPlus) { + initPublicParamsFromDefaultPp(); + FElem e1 = Fp(6); + FElem e2 = Fp(6); + FElem e3 = Fp(3); + e1 = e2 += e3; + EXPECT_EQ(e1, 9); + EXPECT_EQ(e2, 9); + EXPECT_EQ(e3, 3); +} + +TEST(gadgetLib2, FElem_R1P_Elem_operatorMinus) { + initPublicParamsFromDefaultPp(); + FElem e1 = Fp(9); + FElem e2 = Fp(9); + FElem e3 = Fp(3); + e1 = e2 -= e3; + EXPECT_EQ(e1, 6); + EXPECT_EQ(e2, 6); + EXPECT_EQ(e3, 3); +} + +TEST(gadgetLib2, FElem_R1P_Elem_operatorUnaryMinus) { + initPublicParamsFromDefaultPp(); + FElem e2 = Fp(6); + FElem e3 = 3; + e3 = -e2; + EXPECT_EQ(e2, 6); + EXPECT_EQ(e3, -6); + EXPECT_TRUE(e3.fieldType() == R1P); +} + +TEST(gadgetLib2, FElem_R1P_Elem_inverse) { + initPublicParamsFromDefaultPp(); + FElem e42 = Fp(42); + EXPECT_EQ(e42.inverse(R1P),Fp(42).inverse()); +} + +TEST(gadgetLib2, LinearTermConstructors) { + initPublicParamsFromDefaultPp(); + //LinearTerm(const Variable& v) : variable_(v), coeff_(1) {} + VariableArray x(10, "x"); + LinearTerm lt0(x[0]); + VariableAssignment ass; + ass[x[0]] = Fp(42); + EXPECT_EQ(lt0.eval(ass), 42); + EXPECT_NE(lt0.eval(ass), 17); + ass[x[0]] = Fp(2); + EXPECT_EQ(lt0.eval(ass), 2); + LinearTerm lt2(x[2]); + ass[x[2]] = 24; + EXPECT_EQ(lt2.eval(ass), 24); + //LinearTerm(const Variable& v, const FElem& coeff) : variable_(v), coeff_(coeff) {} + LinearTerm lt3(x[3], Fp(3)); + ass[x[3]] = Fp(4); + EXPECT_EQ(lt3.eval(ass), 3 * 4); + //LinearTerm(const Variable& v, long n) : variable_(v), coeff_(n) {} + LinearTerm lt5(x[5], long(2)); + ass[x[5]] = 5; + EXPECT_EQ(lt5.eval(ass), 5 * 2); + LinearTerm lt6(x[6], 2); + ass[x[6]] = 6; + EXPECT_EQ(lt6.eval(ass), 6 * 2); +} + +TEST(gadgetLib2, LinearTermUnaryMinus) { + initPublicParamsFromDefaultPp(); + VariableArray x(10, "x"); + LinearTerm lt6(x[6], 2); + LinearTerm lt7 = -lt6; + VariableAssignment ass; + ass[x[6]] = 6; + EXPECT_EQ(lt7.eval(ass), -6 * 2); +} + +TEST(gadgetLib2, LinearTermFieldType) { + initPublicParamsFromDefaultPp(); + VariableArray x(10, "x"); + LinearTerm lt3(x[3], Fp(3)); + LinearTerm lt6(x[6], 2); + VariableAssignment ass; + ass[x[3]] = Fp(4); + ass[x[6]] = 6; + EXPECT_EQ(lt6.fieldtype(), AGNOSTIC); + EXPECT_EQ(lt3.fieldtype(), R1P); +} + +TEST(gadgetLib2, LinearTermAsString) { + initPublicParamsFromDefaultPp(); + VariableArray x(10, "x"); + VariableAssignment ass; + #ifdef DEBUG + // R1P + LinearTerm lt10(x[0], Fp(-1)); + EXPECT_EQ(lt10.asString(), "-1 * x[0]"); + LinearTerm lt11(x[0], Fp(0)); + EXPECT_EQ(lt11.asString(), "0 * x[0]"); + LinearTerm lt12(x[0], Fp(1)); + EXPECT_EQ(lt12.asString(), "x[0]"); + LinearTerm lt13(x[0], Fp(2)); + EXPECT_EQ(lt13.asString(), "2 * x[0]"); + // AGNOSTIC + LinearTerm lt30(x[0], -1); + EXPECT_EQ(lt30.asString(), "-1 * x[0]"); + LinearTerm lt31(x[0], 0); + EXPECT_EQ(lt31.asString(), "0 * x[0]"); + LinearTerm lt32(x[0], Fp(1)); + EXPECT_EQ(lt32.asString(), "x[0]"); + LinearTerm lt33(x[0], Fp(2)); + EXPECT_EQ(lt33.asString(), "2 * x[0]"); + #endif // DEBUG +} + +TEST(gadgetLib2, LinearTermOperatorTimes) { + initPublicParamsFromDefaultPp(); + VariableArray x(10, "x"); + VariableAssignment ass; + ass[x[0]] = Fp(2); + LinearTerm lt42(x[0], Fp(1)); + LinearTerm lt43(x[0], Fp(2)); + lt42 = lt43 *= FElem(4); + EXPECT_EQ(lt42.eval(ass), 8*2); + EXPECT_EQ(lt43.eval(ass), 8*2); +} + +// TODO refactor this test +TEST(gadgetLib2, LinearCombination) { + initPublicParamsFromDefaultPp(); +// LinearCombination() : linearTerms_(), constant_(0) {} + LinearCombination lc0; + VariableAssignment assignment; + EXPECT_EQ(lc0.eval(assignment),0); +// LinearCombination(const Variable& var) : linearTerms_(1,var), constant_(0) {} + VariableArray x(10,"x"); + LinearCombination lc1(x[1]); + assignment[x[1]] = 42; + EXPECT_EQ(lc1.eval(assignment),42); +// LinearCombination(const LinearTerm& linTerm) : linearTerms_(1,linTerm), constant_(0) {} + LinearTerm lt(x[2], Fp(2)); + LinearCombination lc2 = lt; + assignment[x[2]] = 2; + EXPECT_EQ(lc2.eval(assignment),4); +// LinearCombination(long i) : linearTerms_(), constant_(i) {} + LinearCombination lc3 = 3; + EXPECT_EQ(lc3.eval(assignment),3); +// LinearCombination(const FElem& elem) : linearTerms_(), constant_(elem) {} + FElem elem = Fp(4); + LinearCombination lc4 = elem; + EXPECT_EQ(lc4.eval(assignment),4); +// LinearCombination& operator+=(const LinearCombination& other); + lc1 = lc4 += lc2; + EXPECT_EQ(lc4.eval(assignment),4+4); + EXPECT_EQ(lc1.eval(assignment),4+4); + EXPECT_EQ(lc2.eval(assignment),4); +// LinearCombination& operator-=(const LinearCombination& other); + lc1 = lc4 -= lc3; + EXPECT_EQ(lc4.eval(assignment),4+4-3); + EXPECT_EQ(lc1.eval(assignment),4+4-3); + EXPECT_EQ(lc3.eval(assignment),3); +// ::std::string asString() const; +# ifdef DEBUG + EXPECT_EQ(lc1.asString(), "2 * x[2] + 1"); +# else // ifdef DEBUG + EXPECT_EQ(lc1.asString(), ""); +# endif // ifdef DEBUG +// Variable::set getUsedVariables() const; + Variable::set sVar = lc1.getUsedVariables(); + EXPECT_EQ(sVar.size(),1u); + assignment[x[2]] = 83; + EXPECT_EQ(assignment[*sVar.begin()], 83); + assignment[x[2]] = 2; +// LinearCombination operator-(const LinearCombination& lc); + lc2 = -lc1; + EXPECT_EQ(lc2.eval(assignment),-5); + lc2 = lc1 *= FElem(4); + EXPECT_EQ(lc1.eval(assignment),5*4); + EXPECT_EQ(lc2.eval(assignment),5*4); +} + +TEST(gadgetLib2, MonomialConstructors) { + initPublicParamsFromDefaultPp(); + //Monomial(const Variable& var) : coeff_(1), variables_(1, var) {} + VariableArray x(10, "x"); + Monomial m0 = x[0]; + VariableAssignment assignment; + assignment[x[0]] = 42; + EXPECT_EQ(m0.eval(assignment), 42); + //Monomial(const Variable& var, const FElem& coeff) : coeff_(coeff), variables_(1, var) {} + Monomial m1(x[1], Fp(3)); + assignment[x[1]] = 2; + EXPECT_EQ(m1.eval(assignment), 6); + //Monomial(const LinearTerm& linearTerm); + LinearTerm lt(x[3], 3); + Monomial m3 = lt; + assignment[x[3]] = 3; + EXPECT_EQ(m3.eval(assignment), 9); +} + +TEST(gadgetLib2, MonomialUnaryMinus) { + initPublicParamsFromDefaultPp(); + Variable x("x"); + Monomial m3 = 3 * x; + Monomial m4 = -m3; + VariableAssignment assignment; + assignment[x] = 3; + EXPECT_EQ(m4.eval(assignment), -9); +} + +TEST(gadgetLib2, MonomialOperatorTimes) { + initPublicParamsFromDefaultPp(); + VariableArray x(10, "x"); + Monomial m0 = x[0]; + Monomial m4 = -3 * x[3]; + Monomial m3 = m4 *= m0; + VariableAssignment assignment; + assignment[x[0]] = 42; + assignment[x[3]] = 3; + EXPECT_EQ(m3.eval(assignment), -9 * 42); + EXPECT_EQ(m4.eval(assignment), -9 * 42); + EXPECT_EQ(m0.eval(assignment), 42); +} + +TEST(gadgetLib2, MonomialUsedVariables) { + initPublicParamsFromDefaultPp(); + VariableArray x(10, "x"); + Monomial m0 = x[0]; + Monomial m4 = -3 * x[3]; + Monomial m3 = m4 *= m0; + Variable::set varSet = m3.getUsedVariables(); + ASSERT_EQ(varSet.size(), 2u); + EXPECT_TRUE(varSet.find(x[0]) != varSet.end()); + EXPECT_TRUE(varSet.find(x[3]) != varSet.end()); + EXPECT_TRUE(varSet.find(x[4]) == varSet.end()); +} + +TEST(gadgetLib2, MonomialAsString) { + initPublicParamsFromDefaultPp(); + VariableArray x(10, "x"); + Monomial m0 = x[0]; + Monomial m4 = x[3] * -3; + Monomial m3 = m4 *= m0; +# ifdef DEBUG + EXPECT_EQ(m3.asString(), "-3*x[0]*x[3]"); +# else + EXPECT_EQ(m3.asString(), ""); +# endif +} + +TEST(gadgetLib2, PolynomialConstructors) { + initPublicParamsFromDefaultPp(); + //Polynomial(); + Polynomial p0; + VariableAssignment assignment; + EXPECT_EQ(p0.eval(assignment), 0); + //Polynomial(const Monomial& monomial); + VariableArray x(10, "x"); + Monomial m0(x[0], 3); + Polynomial p1 = m0; + assignment[x[0]] = 2; + EXPECT_EQ(p1.eval(assignment), 6); + //Polynomial(const Variable& var); + Polynomial p2 = x[2]; + assignment[x[2]] = 2; + EXPECT_EQ(p2.eval(assignment), 2); + //Polynomial(const FElem& val); + Polynomial p3 = FElem(Fp(3)); + EXPECT_EQ(p3.eval(assignment), 3); + //Polynomial(const LinearCombination& linearCombination); + LinearCombination lc(x[0]); + lc += x[2]; + Polynomial p4 = lc; + EXPECT_EQ(p4.eval(assignment), 4); + //Polynomial(const LinearTerm& linearTerm); + const LinearTerm lt5 = 5 * x[5]; + Polynomial p5 = lt5; + assignment[x[5]] = 5; + EXPECT_EQ(p5.eval(assignment), 25); +} + +TEST(gadgetLib2, PolynomialUsedVariables) { + initPublicParamsFromDefaultPp(); + VariableArray x(10, "x"); + Polynomial p4 = x[0] + x[2]; + const Variable::set varSet = p4.getUsedVariables(); + EXPECT_EQ(varSet.size(), 2u); + EXPECT_TRUE(varSet.find(x[0]) != varSet.end()); + EXPECT_TRUE(varSet.find(x[2]) != varSet.end()); +} + +TEST(gadgetLib2, PolynomialOperatorPlus) { + initPublicParamsFromDefaultPp(); + VariableArray x(10, "x"); + Polynomial p3 = FElem(Fp(3)); + Polynomial p4 = x[0] + x[2]; + Polynomial p5 = p4 += p3; + VariableAssignment assignment; + assignment[x[0]] = 2; + assignment[x[2]] = 2; + EXPECT_EQ(p5.eval(assignment), 7); +} + +TEST(gadgetLib2, PolynomialAsString) { + initPublicParamsFromDefaultPp(); + VariableArray x(10, "x"); + Polynomial p0; + Polynomial p1 = 3 * x[0]; + Polynomial p2 = x[2]; + Polynomial p3 = FElem(Fp(3)); + Polynomial p4 = x[0] + x[2]; + Polynomial p5 = p4 += p3; +# ifdef DEBUG + EXPECT_EQ(p0.asString(), "0"); + EXPECT_EQ(p1.asString(), "3*x[0]"); + EXPECT_EQ(p2.asString(), "x[2]"); + EXPECT_EQ(p3.asString(), "3"); + EXPECT_EQ(p4.asString(), "x[0] + x[2] + 3"); + EXPECT_EQ(p5.asString(), "x[0] + x[2] + 3"); +# else // DEBUG + EXPECT_EQ(p0.asString(), ""); + EXPECT_EQ(p1.asString(), ""); + EXPECT_EQ(p2.asString(), ""); + EXPECT_EQ(p3.asString(), ""); + EXPECT_EQ(p4.asString(), ""); + EXPECT_EQ(p5.asString(), ""); +# endif // DEBUG +} + +TEST(gadgetLib2, PolynomialOperatorTimes) { + initPublicParamsFromDefaultPp(); + VariableArray x(10, "x"); + VariableAssignment assignment; + assignment[x[0]] = 2; + assignment[x[2]] = 2; + Polynomial p4 = x[0] + x[2]; + Polynomial p5 = p4 += 3; + Polynomial p0 = p4 *= p5; + EXPECT_EQ(p0.eval(assignment), 7 * 7); + EXPECT_EQ(p4.eval(assignment), 7 * 7); + EXPECT_EQ(p5.eval(assignment), 7); +} + +TEST(gadgetLib2, PolynomialOperatorMinus) { + initPublicParamsFromDefaultPp(); + VariableArray x(10, "x"); + Polynomial p0 = x[0]; + Polynomial p1 = x[1]; + Polynomial p2 = 2 * x[2]; + VariableAssignment assignment; + assignment[x[0]] = 0; + assignment[x[1]] = 1; + assignment[x[2]] = 2; + p0 = p1 -= p2; // = x[1] - 2 * x[2] = 1 - 2 * 2 + EXPECT_EQ(p0.eval(assignment), 1 - 2 * 2); + EXPECT_EQ(p1.eval(assignment), 1 - 2 * 2); + EXPECT_EQ(p2.eval(assignment), 2 * 2); +} + +TEST(gadgetLib2, PolynomialUnaryMinus) { + initPublicParamsFromDefaultPp(); + VariableArray x(10, "x"); + Polynomial p0 = x[0]; + Polynomial p1 = x[1]; + VariableAssignment assignment; + assignment[x[0]] = 0; + assignment[x[1]] = 1; + p0 = -p1; + EXPECT_EQ(p0.eval(assignment), -1); + EXPECT_EQ(p1.eval(assignment), 1); +} + +} // namespace diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib2/variable.cpp b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib2/variable.cpp new file mode 100644 index 0000000..89e501f --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib2/variable.cpp @@ -0,0 +1,685 @@ +/** @file + ***************************************************************************** + Implementation of the low level objects needed for field arithmetization. + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include +#include +#include +#include +#include +#include "variable.hpp" +#include "pp.hpp" +#include "infrastructure.hpp" + +using ::std::string; +using ::std::stringstream; +using ::std::set; +using ::std::vector; +using ::std::shared_ptr; +using ::std::cout; +using ::std::endl; +using ::std::dynamic_pointer_cast; + +namespace gadgetlib2 { + + +// Optimization: In the future we may want to port most of the member functions from this file to +// the .hpp files in order to allow for compiler inlining. As inlining has tradeoffs this should be +// profiled before doing so. + +/*************************************************************************************************/ +/*************************************************************************************************/ +/******************* ******************/ +/******************* class FElem ******************/ +/******************* ******************/ +/*************************************************************************************************/ +/*************************************************************************************************/ + +FElem::FElem(const FElemInterface& elem) : elem_(elem.clone()) {} +FElem::FElem() : elem_(new FConst(0)) {} +FElem::FElem(const long n) : elem_(new FConst(n)) {} +FElem::FElem(const int i) : elem_(new FConst(i)) {} +FElem::FElem(const size_t n) : elem_(new FConst(n)) {} +FElem::FElem(const Fp& elem) : elem_(new R1P_Elem(elem)) {} +FElem::FElem(const FElem& src) : elem_(src.elem_->clone()) {} + + +FElem& FElem::operator=(const FElem& other) { + if (fieldType() == other.fieldType() || fieldType() == AGNOSTIC) { + elem_ = other.elem_->clone(); + } else if (other.fieldType() != AGNOSTIC) { + GADGETLIB_FATAL("Attempted to assign field element of incorrect type"); + } else { + *elem_ = dynamic_cast(other.elem_.get())->asLong(); + } + return *this; +} + +FElem& FElem::operator=(FElem&& other) { + if (fieldType() == other.fieldType() || fieldType() == AGNOSTIC) { + elem_ = ::std::move(other.elem_); + } else if (other.elem_->fieldType() != AGNOSTIC) { + GADGETLIB_FATAL("Attempted to move assign field element of incorrect type"); + } else { + *elem_ = dynamic_cast(other.elem_.get())->asLong(); + } + return *this; +} + +bool fieldMustBePromotedForArithmetic(const FieldType& lhsField, const FieldType& rhsField) { + if (lhsField == rhsField) return false; + if (rhsField == AGNOSTIC) return false; + return true; +} + +void FElem::promoteToFieldType(FieldType type) { + if (!fieldMustBePromotedForArithmetic(this->fieldType(), type)) { + return; + } + if(type == R1P) { + const FConst* fConst = dynamic_cast(elem_.get()); + GADGETLIB_ASSERT(fConst != NULL, "Cannot convert between specialized field types."); + elem_.reset(new R1P_Elem(fConst->asLong())); + } else { + GADGETLIB_FATAL("Attempted to promote to unknown field type"); + } +} + +FElem& FElem::operator*=(const FElem& other) { + promoteToFieldType(other.fieldType()); + *elem_ *= *other.elem_; + return *this; +} + +FElem& FElem::operator+=(const FElem& other) { + promoteToFieldType(other.fieldType()); + *elem_ += *other.elem_; + return *this; +} + +FElem& FElem::operator-=(const FElem& other) { + promoteToFieldType(other.fieldType()); + *elem_ -= *other.elem_; return *this; +} + +FElem FElem::inverse(const FieldType& fieldType) { + promoteToFieldType(fieldType); + return FElem(*(elem_->inverse())); +} + +int FElem::getBit(unsigned int i, const FieldType& fieldType) { + promoteToFieldType(fieldType); + if (this->fieldType() == fieldType) { + return elem_->getBit(i); + } else { + GADGETLIB_FATAL("Attempted to extract bits from incompatible field type."); + } +} + +FElem power(const FElem& base, long exponent) { // TODO .cpp + FElem retval(base); + retval.elem_->power(exponent); + return retval; +} + +/***********************************/ +/*** END OF CLASS DEFINITION ***/ +/***********************************/ + +/*************************************************************************************************/ +/*************************************************************************************************/ +/******************* ******************/ +/******************* class FConst ******************/ +/******************* ******************/ +/*************************************************************************************************/ +/*************************************************************************************************/ + +FConst& FConst::operator+=(const FElemInterface& other) { + contents_ += dynamic_cast(other).contents_; + return *this; +} + +FConst& FConst::operator-=(const FElemInterface& other) { + contents_ -= dynamic_cast(other).contents_; + return *this; +} + +FConst& FConst::operator*=(const FElemInterface& other) { + contents_ *= dynamic_cast(other).contents_; + return *this; +} + +FElemInterfacePtr FConst::inverse() const { + GADGETLIB_FATAL("Attempted to invert an FConst element."); +} + +FElemInterface& FConst::power(long exponent) { + contents_ = 0.5 + ::std::pow(double(contents_), double(exponent)); + return *this; +} + + +/***********************************/ +/*** END OF CLASS DEFINITION ***/ +/***********************************/ + +/*************************************************************************************************/ +/*************************************************************************************************/ +/******************* ******************/ +/******************* class R1P_Elem ******************/ +/******************* ******************/ +/*************************************************************************************************/ +/*************************************************************************************************/ + +R1P_Elem& R1P_Elem::operator+=(const FElemInterface& other) { + if (other.fieldType() == R1P) { + elem_ += dynamic_cast(other).elem_; + } else if (other.fieldType() == AGNOSTIC) { + elem_ += dynamic_cast(other).asLong(); + } else { + GADGETLIB_FATAL("Attempted to add incompatible type to R1P_Elem."); + } + return *this; +} + +R1P_Elem& R1P_Elem::operator-=(const FElemInterface& other) { + if (other.fieldType() == R1P) { + elem_ -= dynamic_cast(other).elem_; + } else if (other.fieldType() == AGNOSTIC) { + elem_ -= dynamic_cast(other).asLong(); + } else { + GADGETLIB_FATAL("Attempted to add incompatible type to R1P_Elem."); + } + return *this; +} + +R1P_Elem& R1P_Elem::operator*=(const FElemInterface& other) { + if (other.fieldType() == R1P) { + elem_ *= dynamic_cast(other).elem_; + } else if (other.fieldType() == AGNOSTIC) { + elem_ *= dynamic_cast(other).asLong(); + } else { + GADGETLIB_FATAL("Attempted to add incompatible type to R1P_Elem."); + } + return *this; +} + +bool R1P_Elem::operator==(const FElemInterface& other) const { + const R1P_Elem* pOther = dynamic_cast(&other); + if (pOther) { + return elem_ == pOther->elem_; + } + const FConst* pConst = dynamic_cast(&other); + if (pConst) { + return *this == *pConst; + } + GADGETLIB_FATAL("Attempted to Compare R1P_Elem with incompatible type."); +} + +FElemInterfacePtr R1P_Elem::inverse() const { + return FElemInterfacePtr(new R1P_Elem(elem_.inverse())); +} + +long R1P_Elem::asLong() const { + //GADGETLIB_ASSERT(elem_.as_ulong() <= LONG_MAX, "long overflow occured."); + return long(elem_.as_ulong()); +} + +/***********************************/ +/*** END OF CLASS DEFINITION ***/ +/***********************************/ + +/*************************************************************************************************/ +/*************************************************************************************************/ +/******************* ******************/ +/******************* class Variable ******************/ +/******************* ******************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +VarIndex_t Variable::nextFreeIndex_ = 0; + +#ifdef DEBUG +Variable::Variable(const string& name) : index_(nextFreeIndex_++), name_(name) { + GADGETLIB_ASSERT(nextFreeIndex_ > 0, GADGETLIB2_FMT("Variable index overflow has occured, maximum number of " + "Variables is %lu", ULONG_MAX)); +} +#else +Variable::Variable(const string& name) : index_(nextFreeIndex_++) { + UNUSED(name); + GADGETLIB_ASSERT(nextFreeIndex_ > 0, GADGETLIB2_FMT("Variable index overflow has occured, maximum number of " + "Variables is %lu", ULONG_MAX)); +} +#endif + +Variable::~Variable() {}; + +string Variable::name() const { +# ifdef DEBUG + return name_; +# else + return ""; +# endif +} + +FElem Variable::eval(const VariableAssignment& assignment) const { + try { + return assignment.at(*this); + } catch (::std::out_of_range) { + GADGETLIB_FATAL(GADGETLIB2_FMT("Attempted to evaluate unassigned Variable \"%s\", idx:%lu", name().c_str(), + index_)); + } +} + +/***********************************/ +/*** END OF CLASS DEFINITION ***/ +/***********************************/ + + +/*************************************************************************************************/ +/*************************************************************************************************/ +/******************* ******************/ +/******************* class VariableArray ******************/ +/******************* ******************/ +/*************************************************************************************************/ +/*************************************************************************************************/ + +#ifdef DEBUG +VariableArray::VariableArray(const string& name) : VariableArrayContents(), name_(name) {} +VariableArray::VariableArray(const int size, const ::std::string& name) : VariableArrayContents() { + for (int i = 0; i < size; ++i) { + push_back(Variable(GADGETLIB2_FMT("%s[%d]", name.c_str(), i))); + } +} +VariableArray::VariableArray(const size_t size, const ::std::string& name) : VariableArrayContents() { + for (size_t i = 0; i < size; ++i) { + push_back(Variable(GADGETLIB2_FMT("%s[%d]", name.c_str(), i))); + } +} +::std::string VariableArray::name() const { + return name_; +} + +#else +::std::string VariableArray::name() const { + return ""; +} + +VariableArray::VariableArray(const string& name) : VariableArrayContents() { UNUSED(name); } +VariableArray::VariableArray(const size_t size, const ::std::string& name) + : VariableArrayContents(size) { UNUSED(name); } +VariableArray::VariableArray(const int size, const ::std::string& name) + : VariableArrayContents(size) { UNUSED(name); } +#endif + +/***********************************/ +/*** END OF CLASS DEFINITION ***/ +/***********************************/ + +/*************************************************************************************************/ +/*************************************************************************************************/ +/******************* ******************/ +/******************* Custom Variable classes ******************/ +/******************* ******************/ +/*************************************************************************************************/ +/*************************************************************************************************/ + +MultiPackedWord::MultiPackedWord(const FieldType& fieldType) + : VariableArray(), numBits_(0), fieldType_(fieldType) {} + +MultiPackedWord::MultiPackedWord(const size_t numBits, + const FieldType& fieldType, + const ::std::string& name) + : VariableArray(), numBits_(numBits), fieldType_(fieldType) { + size_t packedSize = getMultipackedSize(); + VariableArray varArray(packedSize, name); + VariableArray::swap(varArray); +} + +void MultiPackedWord::resize(const size_t numBits) { + numBits_ = numBits; + size_t packedSize = getMultipackedSize(); + VariableArray::resize(packedSize); +} + +size_t MultiPackedWord::getMultipackedSize() const { + size_t packedSize = 0; + if (fieldType_ == R1P) { + packedSize = 1; // TODO add assertion that numBits can fit in the field characteristic + } else { + GADGETLIB_FATAL("Unknown field type for packed variable."); + } + return packedSize; +} + +DualWord::DualWord(const size_t numBits, + const FieldType& fieldType, + const ::std::string& name) + : multipacked_(numBits, fieldType, name + "_p"), + unpacked_(numBits, name + "_u") {} + +DualWord::DualWord(const MultiPackedWord& multipacked, const UnpackedWord& unpacked) + : multipacked_(multipacked), unpacked_(unpacked) {} + +void DualWord::resize(size_t newSize) { + multipacked_.resize(newSize); + unpacked_.resize(newSize); +} + +DualWordArray::DualWordArray(const FieldType& fieldType) + : multipackedContents_(0, MultiPackedWord(fieldType)), unpackedContents_(0), + numElements_(0) {} + +DualWordArray::DualWordArray(const MultiPackedWordArray& multipackedContents, // TODO delete, for dev + const UnpackedWordArray& unpackedContents) + : multipackedContents_(multipackedContents), unpackedContents_(unpackedContents), + numElements_(multipackedContents_.size()) { + GADGETLIB_ASSERT(multipackedContents_.size() == numElements_, + "Dual Variable multipacked contents size mismatch"); + GADGETLIB_ASSERT(unpackedContents_.size() == numElements_, + "Dual Variable packed contents size mismatch"); +} + +MultiPackedWordArray DualWordArray::multipacked() const {return multipackedContents_;} +UnpackedWordArray DualWordArray::unpacked() const {return unpackedContents_;} +PackedWordArray DualWordArray::packed() const { + GADGETLIB_ASSERT(numElements_ == multipackedContents_.size(), "multipacked contents size mismatch") + PackedWordArray retval(numElements_); + for(size_t i = 0; i < numElements_; ++i) { + const auto element = multipackedContents_[i]; + GADGETLIB_ASSERT(element.size() == 1, "Cannot convert from multipacked to packed"); + retval[i] = element[0]; + } + return retval; +} + +void DualWordArray::push_back(const DualWord& dualWord) { + multipackedContents_.push_back(dualWord.multipacked()); + unpackedContents_.push_back(dualWord.unpacked()); + ++numElements_; +} + +DualWord DualWordArray::at(size_t i) const { + //const MultiPackedWord multipackedRep = multipacked()[i]; + //const UnpackedWord unpackedRep = unpacked()[i]; + //const DualWord retval(multipackedRep, unpackedRep); + //return retval; + return DualWord(multipacked()[i], unpacked()[i]); +} + +size_t DualWordArray::size() const { + GADGETLIB_ASSERT(multipackedContents_.size() == numElements_, + "Dual Variable multipacked contents size mismatch"); + GADGETLIB_ASSERT(unpackedContents_.size() == numElements_, + "Dual Variable packed contents size mismatch"); + return numElements_; +} + +/*************************************************************************************************/ +/*************************************************************************************************/ +/******************* ******************/ +/******************* class LinearTerm ******************/ +/******************* ******************/ +/*************************************************************************************************/ +/*************************************************************************************************/ + +::std::string LinearTerm::asString() const { + if (coeff_ == 1) { return variable_.name();} + else if (coeff_ == -1) {return GADGETLIB2_FMT("-1 * %s", variable_.name().c_str());} + else if (coeff_ == 0) {return GADGETLIB2_FMT("0 * %s", variable_.name().c_str());} + else {return GADGETLIB2_FMT("%s * %s", coeff_.asString().c_str(), variable_.name().c_str());} +} + +FElem LinearTerm::eval(const VariableAssignment& assignment) const { + return FElem(coeff_) *= variable_.eval(assignment); +} + +/***********************************/ +/*** END OF CLASS DEFINITION ***/ +/***********************************/ + +/*************************************************************************************************/ +/*************************************************************************************************/ +/******************* ******************/ +/******************* class LinearCombination ******************/ +/******************* ******************/ +/*************************************************************************************************/ +/*************************************************************************************************/ + +LinearCombination& LinearCombination::operator+=(const LinearCombination& other) { + linearTerms_.insert(linearTerms_.end(), other.linearTerms_.cbegin(), other.linearTerms_.cend()); + constant_ += other.constant_; + return *this; +} + +LinearCombination& LinearCombination::operator-=(const LinearCombination& other) { + for(const LinearTerm& lt : other.linearTerms_) { + linearTerms_.push_back(-lt); + } + constant_ -= other.constant_; + return *this; +} + +LinearCombination& LinearCombination::operator*=(const FElem& other) { + constant_ *= other; + for (LinearTerm& lt : linearTerms_) { + lt *= other; + } + return *this; +} + +FElem LinearCombination::eval(const VariableAssignment& assignment) const { + FElem evaluation = constant_; + for(const LinearTerm& lt : linearTerms_) { + evaluation += lt.eval(assignment); + } + return evaluation; +} + +::std::string LinearCombination::asString() const { +#ifdef DEBUG + ::std::string retval; + auto it = linearTerms_.begin(); + if (it == linearTerms_.end()) { + return constant_.asString(); + } else { + retval += it->asString(); + } + for(++it; it != linearTerms_.end(); ++it) { + retval += " + " + it->asString(); + } + if (constant_ != 0) { + retval += " + " + constant_.asString(); + } + return retval; +#else // ifdef DEBUG + return ""; +#endif // ifdef DEBUG +} + +const Variable::set LinearCombination::getUsedVariables() const { + Variable::set retSet; + for(const LinearTerm& lt : linearTerms_) { + retSet.insert(lt.variable()); + } + return retSet; +} + +/***********************************/ +/*** END OF CLASS DEFINITION ***/ +/***********************************/ + +LinearCombination sum(const VariableArray& inputs) { + LinearCombination retval(0); + for(const Variable& var : inputs) { + retval += var; + } + return retval; +} + +LinearCombination negate(const LinearCombination& lc) { + return (1 - lc); +} + +/*************************************************************************************************/ +/*************************************************************************************************/ +/******************* ******************/ +/******************* class Monomial ******************/ +/******************* ******************/ +/*************************************************************************************************/ +/*************************************************************************************************/ + +Monomial::Monomial(const LinearTerm& linearTerm) + : coeff_(linearTerm.coeff_), variables_() {variables_.insert(linearTerm.variable_);} + +FElem Monomial::eval(const VariableAssignment& assignment) const { + FElem retval = coeff_; + for(const Variable& var : variables_) { + retval *= var.eval(assignment); + } + return retval; +} + +const Variable::set Monomial::getUsedVariables() const { + return Variable::set(variables_.begin(), variables_.end()); +} + +const FElem Monomial::getCoefficient() const{ + return coeff_; +} + +::std::string Monomial::asString() const { +#ifdef DEBUG + if (variables_.size() == 0) { + return coeff_.asString(); + } + string retval; + if (coeff_ != 1) { + retval += coeff_.asString() + "*"; + } + auto iter = variables_.begin(); + retval += iter->name(); + for(++iter; iter != variables_.end(); ++iter) { + retval += "*" + iter->name(); + } + return retval; +#else // ifdef DEBUG + return ""; +#endif // ifdef DEBUG +} + +Monomial Monomial::operator-() const { + Monomial retval = *this; + retval.coeff_ = -retval.coeff_; + return retval; +} + +Monomial& Monomial::operator*=(const Monomial& other) { + coeff_ *= other.coeff_; + variables_.insert(other.variables_.begin(), other.variables_.end()); + return *this; +} + +/***********************************/ +/*** END OF CLASS DEFINITION ***/ +/***********************************/ + + +/*************************************************************************************************/ +/*************************************************************************************************/ +/******************* ******************/ +/******************* class Polynomial ******************/ +/******************* ******************/ +/*************************************************************************************************/ +/*************************************************************************************************/ + +Polynomial::Polynomial(const LinearCombination& linearCombination) + : monomials_(), constant_(linearCombination.constant_) { + for (const LinearTerm& linearTerm : linearCombination.linearTerms_) { + monomials_.push_back(Monomial(linearTerm)); + } +} + +FElem Polynomial::eval(const VariableAssignment& assignment) const { + FElem retval = constant_; + for(const Monomial& monomial : monomials_) { + retval += monomial.eval(assignment); + } + return retval; +} + +const Variable::set Polynomial::getUsedVariables() const { + Variable::set retset; + for(const Monomial& monomial : monomials_) { + const Variable::set curSet = monomial.getUsedVariables(); + retset.insert(curSet.begin(), curSet.end()); + } + return retset; +} + +const vector& Polynomial::getMonomials()const{ + return monomials_; +} + +const FElem Polynomial::getConstant()const{ + return constant_; +} + +::std::string Polynomial::asString() const { +# ifndef DEBUG + return ""; +# endif + if (monomials_.size() == 0) { + return constant_.asString(); + } + string retval; + auto iter = monomials_.begin(); + retval += iter->asString(); + for(++iter; iter != monomials_.end(); ++iter) { + retval += " + " + iter->asString(); + } + if (constant_ != 0) { + retval += " + " + constant_.asString(); + } + return retval; +} + +Polynomial& Polynomial::operator+=(const Polynomial& other) { + constant_ += other.constant_; + monomials_.insert(monomials_.end(), other.monomials_.begin(), other.monomials_.end()); + return *this; +} + +Polynomial& Polynomial::operator*=(const Polynomial& other) { + vector newMonomials; + for(const Monomial& thisMonomial : monomials_) { + for (const Monomial& otherMonomial : other.monomials_) { + newMonomials.push_back(thisMonomial * otherMonomial); + } + newMonomials.push_back(thisMonomial * other.constant_); + } + for (const Monomial& otherMonomial : other.monomials_) { + newMonomials.push_back(otherMonomial * this->constant_); + } + constant_ *= other.constant_; + monomials_ = ::std::move(newMonomials); + return *this; +} + +Polynomial& Polynomial::operator-=(const Polynomial& other) { + constant_ -= other.constant_; + for(const Monomial& otherMonomial : other.monomials_) { + monomials_.push_back(-otherMonomial); + } + return *this; +} + +/***********************************/ +/*** END OF CLASS DEFINITION ***/ +/***********************************/ + +} // namespace gadgetlib2 diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib2/variable.hpp b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib2/variable.hpp new file mode 100644 index 0000000..a09e913 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib2/variable.hpp @@ -0,0 +1,572 @@ +/** @file + ***************************************************************************** + Declaration of the low level objects needed for field arithmetization. + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef LIBSNARK_GADGETLIB2_INCLUDE_GADGETLIB2_VARIABLE_HPP_ +#define LIBSNARK_GADGETLIB2_INCLUDE_GADGETLIB2_VARIABLE_HPP_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "pp.hpp" +#include "infrastructure.hpp" + +namespace gadgetlib2 { + +class GadgetLibAdapter; + +// Forward declarations +class Protoboard; +class FElemInterface; +class FElem; +class FConst; +class Variable; +class VariableArray; + +typedef enum {R1P, AGNOSTIC} FieldType; + +typedef ::std::shared_ptr VariablePtr; +typedef ::std::shared_ptr VariableArrayPtr; +typedef ::std::unique_ptr FElemInterfacePtr; +typedef ::std::shared_ptr ProtoboardPtr; +typedef unsigned long VarIndex_t; + +// Naming Conventions: +// R1P == Rank 1 Prime characteristic + +/*************************************************************************************************/ +/*************************************************************************************************/ +/******************* ******************/ +/******************* class FElemInterface ******************/ +/******************* ******************/ +/*************************************************************************************************/ +/*************************************************************************************************/ + +/** + An interface class for field elements. + Currently 2 classes will derive from this interface: + R1P_Elem - Elements of a field of prime characteristic + FConst - Formally not a field, only placeholders for field agnostic constants, such as 0 and 1. + Can be used for -1 or any other constant which makes semantic sense in all fields. + */ +class FElemInterface { +public: + virtual FElemInterface& operator=(const long n) = 0; + /// FConst will be field agnostic, allowing us to hold values such as 0 and 1 without knowing + /// the underlying field. This assignment operator will convert to the correct field element. + virtual FElemInterface& operator=(const FConst& src) = 0; + virtual ::std::string asString() const = 0; + virtual FieldType fieldType() const = 0; + virtual FElemInterface& operator+=(const FElemInterface& other) = 0; + virtual FElemInterface& operator-=(const FElemInterface& other) = 0; + virtual FElemInterface& operator*=(const FElemInterface& other) = 0; + virtual bool operator==(const FElemInterface& other) const = 0; + virtual bool operator==(const FConst& other) const = 0; + /// This operator is not always mathematically well defined. 'n' will be checked in runtime + /// for fields in which integer values are not well defined. + virtual bool operator==(const long n) const = 0; + /// @returns a unique_ptr to a copy of the current element. + virtual FElemInterfacePtr clone() const = 0; + virtual FElemInterfacePtr inverse() const = 0; + virtual long asLong() const = 0; + virtual int getBit(unsigned int i) const = 0; + virtual FElemInterface& power(long exponent) = 0; + virtual ~FElemInterface(){}; +}; // class FElemInterface + +/***********************************/ +/*** END OF CLASS DEFINITION ***/ +/***********************************/ + +inline bool operator==(const long first, const FElemInterface& second) {return second == first;} +inline bool operator!=(const long first, const FElemInterface& second) {return !(first == second);} +inline bool operator!=(const FElemInterface& first, const long second) {return !(first == second);} +inline bool operator!=(const FElemInterface& first, const FElemInterface& second) { + return !(first == second); +} + +/*************************************************************************************************/ +/*************************************************************************************************/ +/******************* ******************/ +/******************* class FElem ******************/ +/******************* ******************/ +/*************************************************************************************************/ +/*************************************************************************************************/ + +/// A wrapper class for field elements. Can hold any derived type of FieldElementInterface +class FElem { +private: + FElemInterfacePtr elem_; + +public: + explicit FElem(const FElemInterface& elem); + /// Helper method. When doing arithmetic between a constant and a field specific element + /// we want to "promote" the constant to the same field. This function changes the unique_ptr + /// to point to a field specific element with the same value as the constant which it held. + void promoteToFieldType(FieldType type); + FElem(); + FElem(const long n); + FElem(const int i); + FElem(const size_t n); + FElem(const Fp& elem); + FElem(const FElem& src); + + FElem& operator=(const FElem& other); + FElem& operator=(FElem&& other); + FElem& operator=(const long i) { *elem_ = i; return *this;} + ::std::string asString() const {return elem_->asString();} + FieldType fieldType() const {return elem_->fieldType();} + bool operator==(const FElem& other) const {return *elem_ == *other.elem_;} + FElem& operator*=(const FElem& other); + FElem& operator+=(const FElem& other); + FElem& operator-=(const FElem& other); + FElem operator-() const {FElem retval(0); retval -= FElem(*elem_); return retval;} + FElem inverse(const FieldType& fieldType); + long asLong() const {return elem_->asLong();} + int getBit(unsigned int i, const FieldType& fieldType); + friend FElem power(const FElem& base, long exponent); + + inline friend ::std::ostream& operator<<(::std::ostream& os, const FElem& elem) { + return os << elem.elem_->asString(); + } + + friend class GadgetLibAdapter; +}; // class FElem + +inline bool operator!=(const FElem& first, const FElem& second) {return !(first == second);} + +/// These operators are not always mathematically well defined. The long will be checked in runtime +/// for fields in which values other than 0 and 1 are not well defined. +inline bool operator==(const FElem& first, const long second) {return first == FElem(second);} +inline bool operator==(const long first, const FElem& second) {return second == first;} +inline bool operator!=(const FElem& first, const long second) {return !(first == second);} +inline bool operator!=(const long first, const FElem& second) {return !(first == second);} + +/***********************************/ +/*** END OF CLASS DEFINITION ***/ +/***********************************/ + +/*************************************************************************************************/ +/*************************************************************************************************/ +/******************* ******************/ +/******************* class FConst ******************/ +/******************* ******************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +/** + A field agnostic constant. All fields have constants 1 and 0 and this class allows us to hold + an element agnostically while the context field is not known. For example, when given the + very useful expression '1 - x' where x is a field agnostic formal variable, we must store the + constant '1' without knowing over which field this expression will be evaluated. + Constants can also hold integer values, which will be evaluated if possible, in runtime. For + instance the expression '42 + x' will be evaluated in runtime in the trivial way when working + over the prime characteristic Galois Field GF_43 but will cause a runtime error when evaluated + over a GF2 extension field in which '42' has no obvious meaning, other than being the answer to + life, the universe and everything. +*/ +class FConst : public FElemInterface { +private: + long contents_; + explicit FConst(const long n) : contents_(n) {} +public: + virtual FConst& operator=(const long n) {contents_ = n; return *this;} + virtual FConst& operator=(const FConst& src) {contents_ = src.contents_; return *this;} + virtual ::std::string asString() const {return GADGETLIB2_FMT("%ld",contents_);} + virtual FieldType fieldType() const {return AGNOSTIC;} + virtual FConst& operator+=(const FElemInterface& other); + virtual FConst& operator-=(const FElemInterface& other); + virtual FConst& operator*=(const FElemInterface& other); + virtual bool operator==(const FElemInterface& other) const {return other == *this;} + virtual bool operator==(const FConst& other) const {return contents_ == other.contents_;} + virtual bool operator==(const long n) const {return contents_ == n;} + /// @return a unique_ptr to a new copy of the element + virtual FElemInterfacePtr clone() const {return FElemInterfacePtr(new FConst(*this));} + /// @return a unique_ptr to a new copy of the element's multiplicative inverse + virtual FElemInterfacePtr inverse() const; + long asLong() const {return contents_;} + int getBit(unsigned int i) const { UNUSED(i); GADGETLIB_FATAL("Cannot get bit from FConst."); } + virtual FElemInterface& power(long exponent); + + friend class FElem; // allow constructor call +}; // class FConst + +/***********************************/ +/*** END OF CLASS DEFINITION ***/ +/***********************************/ + +/*************************************************************************************************/ +/*************************************************************************************************/ +/******************* ******************/ +/******************* class R1P_Elem ******************/ +/******************* ******************/ +/*************************************************************************************************/ +/*************************************************************************************************/ +/** + Holds elements of a prime characteristic field. Currently implemented using the gmp (linux) and + mpir (windows) libraries. + */ +class R1P_Elem : public FElemInterface { +private: + Fp elem_; +public: + + explicit R1P_Elem(const Fp& elem) : elem_(elem) {} + virtual R1P_Elem& operator=(const FConst& src) {elem_ = src.asLong(); return *this;} + virtual R1P_Elem& operator=(const long n) {elem_ = Fp(n); return *this;} + virtual ::std::string asString() const {return GADGETLIB2_FMT("%u", elem_.as_ulong());} + virtual FieldType fieldType() const {return R1P;} + virtual R1P_Elem& operator+=(const FElemInterface& other); + virtual R1P_Elem& operator-=(const FElemInterface& other); + virtual R1P_Elem& operator*=(const FElemInterface& other); + virtual bool operator==(const FElemInterface& other) const; + virtual bool operator==(const FConst& other) const {return elem_ == Fp(other.asLong());} + virtual bool operator==(const long n) const {return elem_ == Fp(n);} + /// @return a unique_ptr to a new copy of the element + virtual FElemInterfacePtr clone() const {return FElemInterfacePtr(new R1P_Elem(*this));} + /// @return a unique_ptr to a new copy of the element's multiplicative inverse + virtual FElemInterfacePtr inverse() const; + long asLong() const; + int getBit(unsigned int i) const {return elem_.as_bigint().test_bit(i);} + virtual FElemInterface& power(long exponent) {elem_^= exponent; return *this;} + + friend class FElem; // allow constructor call + friend class GadgetLibAdapter; +}; + +/***********************************/ +/*** END OF CLASS DEFINITION ***/ +/***********************************/ + +/*************************************************************************************************/ +/*************************************************************************************************/ +/******************* ******************/ +/******************* class Variable ******************/ +/******************* ******************/ +/*************************************************************************************************/ +/*************************************************************************************************/ + +/** + @brief A formal variable, field agnostic. + + Each variable is specified by an index. This can be imagined as the index in x_1, x_2,..., x_i + These are formal variables and do not hold an assignment, later the class VariableAssignment + will give each formal variable its own assignment. + Variables have no comparison and assignment operators as evaluating (x_1 == x_2) has no sense + without specific assignments. + Variables are field agnostic, this means they can be used regardless of the context field, + which will also be determined by the assignment. + */ +class Variable { +private: + VarIndex_t index_; ///< This index differentiates and identifies Variable instances. + static VarIndex_t nextFreeIndex_; ///< Monotonically-increasing counter to allocate disinct indices. +#ifdef DEBUG + ::std::string name_; +#endif + + /** + * @brief allocates the variable + */ +public: + explicit Variable(const ::std::string& name = ""); + virtual ~Variable(); + + ::std::string name() const; + + /// A functor for strict ordering of Variables. Needed for STL containers. + /// This is not an ordering of Variable assignments and has no semantic meaning. + struct VariableStrictOrder { + bool operator()(const Variable& first, const Variable& second)const { + return first.index_ < second.index_; + } + }; + + typedef ::std::map VariableAssignment; + FElem eval(const VariableAssignment& assignment) const; + + /// A set of Variables should be declared as follows: Variable::set s1; + typedef ::std::set set; + typedef ::std::multiset multiset; + + friend class GadgetLibAdapter; +}; // class Variable +/***********************************/ +/*** END OF CLASS DEFINITION ***/ +/***********************************/ + +typedef ::std::map VariableAssignment; + +/*************************************************************************************************/ +/*************************************************************************************************/ +/******************* ******************/ +/******************* class VariableArray ******************/ +/******************* ******************/ +/*************************************************************************************************/ +/*************************************************************************************************/ + +typedef ::std::vector VariableArrayContents; + +class VariableArray : public VariableArrayContents { +private: +# ifdef DEBUG + ::std::string name_; +# endif +public: + explicit VariableArray(const ::std::string& name = ""); + explicit VariableArray(const int size, const ::std::string& name = ""); + explicit VariableArray(const size_t size, const ::std::string& name = ""); + explicit VariableArray(const size_t size, const Variable& contents) + : VariableArrayContents(size, contents) {} + + using VariableArrayContents::operator[]; + using VariableArrayContents::at; + using VariableArrayContents::push_back; + using VariableArrayContents::size; + + ::std::string name() const; +}; // class VariableArray + +/***********************************/ +/*** END OF CLASS DEFINITION ***/ +/***********************************/ + +/*************************************************************************************************/ +/*************************************************************************************************/ +/******************* ******************/ +/******************* Custom Variable classes ******************/ +/******************* ******************/ +/*************************************************************************************************/ +/*************************************************************************************************/ + +typedef Variable FlagVariable; ///< Holds variable whos purpose is to be populated with a boolean + ///< value, Field(0) or Field(1) +typedef VariableArray FlagVariableArray; +typedef Variable PackedWord; ///< Represents a packed word that can fit in a field element. + ///< For a word representing an unsigned integer for instance this + ///< means we require (int < fieldSize) +typedef VariableArray PackedWordArray; + +/// Holds variables whos purpose is to be populated with the unpacked form of some word, bit by bit +class UnpackedWord : public VariableArray { +public: + UnpackedWord() : VariableArray() {} + UnpackedWord(const size_t numBits, const ::std::string& name) : VariableArray(numBits, name) {} +}; // class UnpackedWord + +typedef ::std::vector UnpackedWordArray; + +/// Holds variables whos purpose is to be populated with the packed form of some word. +/// word representation can be larger than a single field element in small enough fields +class MultiPackedWord : public VariableArray { +private: + size_t numBits_; + FieldType fieldType_; + size_t getMultipackedSize() const; +public: + MultiPackedWord(const FieldType& fieldType = AGNOSTIC); + MultiPackedWord(const size_t numBits, const FieldType& fieldType, const ::std::string& name); + void resize(const size_t numBits); + ::std::string name() const {return VariableArray::name();} +}; // class MultiPackedWord + +typedef ::std::vector MultiPackedWordArray; + +/// Holds both representations of a word, both multipacked and unpacked +class DualWord { +private: + MultiPackedWord multipacked_; + UnpackedWord unpacked_; +public: + DualWord(const FieldType& fieldType) : multipacked_(fieldType), unpacked_() {} + DualWord(const size_t numBits, const FieldType& fieldType, const ::std::string& name); + DualWord(const MultiPackedWord& multipacked, const UnpackedWord& unpacked); + MultiPackedWord multipacked() const {return multipacked_;} + UnpackedWord unpacked() const {return unpacked_;} + FlagVariable bit(size_t i) const {return unpacked_[i];} //syntactic sugar, same as unpacked()[i] + size_t numBits() const { return unpacked_.size(); } + void resize(size_t newSize); +}; // class DualWord + +class DualWordArray { +private: + // kept as 2 seperate arrays because the more common usecase will be to request one of these, + // and not dereference a specific DualWord + MultiPackedWordArray multipackedContents_; + UnpackedWordArray unpackedContents_; + size_t numElements_; +public: + DualWordArray(const FieldType& fieldType); + DualWordArray(const MultiPackedWordArray& multipackedContents, // TODO delete, for dev + const UnpackedWordArray& unpackedContents); + MultiPackedWordArray multipacked() const; + UnpackedWordArray unpacked() const; + PackedWordArray packed() const; //< For cases in which we can assume each unpacked value fits + //< in 1 packed Variable + void push_back(const DualWord& dualWord); + DualWord at(size_t i) const; + size_t size() const; +}; // class DualWordArray + + +/*************************************************************************************************/ +/*************************************************************************************************/ +/******************* ******************/ +/******************* class LinearTerm ******************/ +/******************* ******************/ +/*************************************************************************************************/ +/*************************************************************************************************/ + +class LinearTerm { +private: + Variable variable_; + FElem coeff_; +public: + LinearTerm(const Variable& v) : variable_(v), coeff_(1) {} + LinearTerm(const Variable& v, const FElem& coeff) : variable_(v), coeff_(coeff) {} + LinearTerm(const Variable& v, long n) : variable_(v), coeff_(n) {} + LinearTerm operator-() const {return LinearTerm(variable_, -coeff_);} + LinearTerm& operator*=(const FElem& other) {coeff_ *= other; return *this;} + FieldType fieldtype() const {return coeff_.fieldType();} + ::std::string asString() const; + FElem eval(const VariableAssignment& assignment) const; + Variable variable() const {return variable_;} + + friend class Monomial; + friend class GadgetLibAdapter; +}; // class LinearTerm + +/***********************************/ +/*** END OF CLASS DEFINITION ***/ +/***********************************/ + + + +/*************************************************************************************************/ +/*************************************************************************************************/ +/******************* ******************/ +/******************* class LinearCombination ******************/ +/******************* ******************/ +/*************************************************************************************************/ +/*************************************************************************************************/ + +class LinearCombination { +protected: + ::std::vector linearTerms_; + FElem constant_; + typedef ::std::vector::size_type size_type; +public: + LinearCombination() : linearTerms_(), constant_(0) {} + LinearCombination(const Variable& var) : linearTerms_(1,var), constant_(0) {} + LinearCombination(const LinearTerm& linTerm) : linearTerms_(1,linTerm), constant_(0) {} + LinearCombination(long i) : linearTerms_(), constant_(i) {} + LinearCombination(const FElem& elem) : linearTerms_(), constant_(elem) {} + + LinearCombination& operator+=(const LinearCombination& other); + LinearCombination& operator-=(const LinearCombination& other); + LinearCombination& operator*=(const FElem& other); + FElem eval(const VariableAssignment& assignment) const; + ::std::string asString() const; + const Variable::set getUsedVariables() const; + + friend class Polynomial; + friend class GadgetLibAdapter; +}; // class LinearCombination + +/***********************************/ +/*** END OF CLASS DEFINITION ***/ +/***********************************/ + +inline LinearCombination operator-(const LinearCombination& lc){return LinearCombination(0) -= lc;} + +LinearCombination sum(const VariableArray& inputs); +//TODO : change this to member function +LinearCombination negate(const LinearCombination& lc); + +/*************************************************************************************************/ +/*************************************************************************************************/ +/******************* ******************/ +/******************* class Monomial ******************/ +/******************* ******************/ +/*************************************************************************************************/ +/*************************************************************************************************/ + +class Monomial { +private: + FElem coeff_; + Variable::multiset variables_; // currently just a vector of variables. This can + // surely be optimized e.g. hold a variable-degree pair + // but is not needed for concrete efficiency as we will + // only be invoking degree 2 constraints in the near + // future. +public: + Monomial(const Variable& var) : coeff_(1), variables_() {variables_.insert(var);} + Monomial(const Variable& var, const FElem& coeff) : coeff_(coeff), variables_() {variables_.insert(var);} + Monomial(const FElem& val) : coeff_(val), variables_() {} + Monomial(const LinearTerm& linearTerm); + + FElem eval(const VariableAssignment& assignment) const; + const Variable::set getUsedVariables() const; + const FElem getCoefficient() const; + ::std::string asString() const; + Monomial operator-() const; + Monomial& operator*=(const Monomial& other); +}; // class Monomial + +/***********************************/ +/*** END OF CLASS DEFINITION ***/ +/***********************************/ + + +/*************************************************************************************************/ +/*************************************************************************************************/ +/******************* ******************/ +/******************* class Polynomial ******************/ +/******************* ******************/ +/*************************************************************************************************/ +/*************************************************************************************************/ + +class Polynomial { +private: + ::std::vector monomials_; + FElem constant_; +public: + Polynomial() : monomials_(), constant_(0) {} + Polynomial(const Monomial& monomial) : monomials_(1, monomial), constant_(0) {} + Polynomial(const Variable& var) : monomials_(1, Monomial(var)), constant_(0) {} + Polynomial(const FElem& val) : monomials_(), constant_(val) {} + Polynomial(const LinearCombination& linearCombination); + Polynomial(const LinearTerm& linearTerm) : monomials_(1, Monomial(linearTerm)), constant_(0) {} + Polynomial(int i) : monomials_(), constant_(i) {} + + FElem eval(const VariableAssignment& assignment) const; + const Variable::set getUsedVariables() const; + const std::vector& getMonomials()const; + const FElem getConstant()const; + ::std::string asString() const; + Polynomial& operator+=(const Polynomial& other); + Polynomial& operator*=(const Polynomial& other); + Polynomial& operator-=(const Polynomial& other); + Polynomial& operator+=(const LinearTerm& other) {return *this += Polynomial(Monomial(other));} +}; // class Polynomial + +/***********************************/ +/*** END OF CLASS DEFINITION ***/ +/***********************************/ + +inline Polynomial operator-(const Polynomial& src) {return Polynomial(FElem(0)) -= src;} + +} // namespace gadgetlib2 + +#include "variable_operators.hpp" + +#endif // LIBSNARK_GADGETLIB2_INCLUDE_GADGETLIB2_VARIABLE_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/gadgetlib2/variable_operators.hpp b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib2/variable_operators.hpp new file mode 100644 index 0000000..87f2343 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/gadgetlib2/variable_operators.hpp @@ -0,0 +1,225 @@ +/** @file + ***************************************************************************** + Holds all of the arithmetic operators for the classes declared in variable.hpp . + + This take clutter out of variable.hpp while leaving the * operators in a header file, + thus allowing them to be inlined, for optimization purposes. + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef LIBSNARK_GADGETLIB2_INCLUDE_GADGETLIB2_VARIABLEOPERATORS_HPP_ +#define LIBSNARK_GADGETLIB2_INCLUDE_GADGETLIB2_VARIABLEOPERATORS_HPP_ + +#include "variable.hpp" + +namespace gadgetlib2 { + +/*************************************************************************************************/ +/*************************************************************************************************/ +/******************* ******************/ +/******************* lots o' operators ******************/ +/******************* ******************/ +/*************************************************************************************************/ +/*************************************************************************************************/ + +/***********************************/ +/*** operator+ ***/ +/***********************************/ + +// Polynomial +inline Polynomial operator+(const Polynomial& first, const Polynomial& second) {auto retval = first; return retval += second;} + +// Monomial +inline Polynomial operator+(const Monomial& first, const Polynomial& second) {return Polynomial(first) + second;} +inline Polynomial operator+(const Monomial& first, const Monomial& second) {return Polynomial(first) + Polynomial(second);} + +// LinearCombination +inline Polynomial operator+(const LinearCombination& first, const Polynomial& second) {return Polynomial(first) + second;} +inline Polynomial operator+(const LinearCombination& first, const Monomial& second) {return Polynomial(first) + second;} +inline LinearCombination operator+(const LinearCombination& first, const LinearCombination& second) {auto retval = first; return retval += second;} + +// LinearTerm +inline Polynomial operator+(const LinearTerm& first, const Polynomial& second) {return LinearCombination(first) + second;} +inline Polynomial operator+(const LinearTerm& first, const Monomial& second) {return LinearCombination(first) + second;} +inline LinearCombination operator+(const LinearTerm& first, const LinearCombination& second) {return LinearCombination(first) + second;} +inline LinearCombination operator+(const LinearTerm& first, const LinearTerm& second) {return LinearCombination(first) + LinearCombination(second);} + +// Variable +inline Polynomial operator+(const Variable& first, const Polynomial& second) {return LinearTerm(first) + second;} +inline Polynomial operator+(const Variable& first, const Monomial& second) {return LinearTerm(first) + second;} +inline LinearCombination operator+(const Variable& first, const LinearCombination& second) {return LinearTerm(first) + second;} +inline LinearCombination operator+(const Variable& first, const LinearTerm& second) {return LinearTerm(first) + second;} +inline LinearCombination operator+(const Variable& first, const Variable& second) {return LinearTerm(first) + LinearTerm(second);} + +// FElem +inline Polynomial operator+(const FElem& first, const Polynomial& second) {return LinearCombination(first) + second;} +inline Polynomial operator+(const FElem& first, const Monomial& second) {return LinearCombination(first) + second;} +inline LinearCombination operator+(const FElem& first, const LinearCombination& second) {return LinearCombination(first) + second;} +inline LinearCombination operator+(const FElem& first, const LinearTerm& second) {return LinearCombination(first) + LinearCombination(second);} +inline LinearCombination operator+(const FElem& first, const Variable& second) {return LinearCombination(first) + LinearCombination(second);} +inline FElem operator+(const FElem& first, const FElem& second) {auto retval = first; return retval += second;} + +// int +inline FElem operator+(const int first, const FElem& second) {return FElem(first) + second;} +inline LinearCombination operator+(const int first, const Variable& second) {return FElem(first) + second;} +inline LinearCombination operator+(const int first, const LinearTerm& second) {return FElem(first) + second;} +inline LinearCombination operator+(const int first, const LinearCombination& second) {return FElem(first) + second;} +inline Polynomial operator+(const int first, const Monomial& second) {return FElem(first) + second;} +inline Polynomial operator+(const int first, const Polynomial& second) {return FElem(first) + second;} + +// symetrical operators +inline Polynomial operator+(const Polynomial& first, const Monomial& second) {return second + first;} +inline Polynomial operator+(const Monomial& first, const LinearCombination& second) {return second + first;} +inline Polynomial operator+(const Polynomial& first, const LinearCombination& second) {return second + first;} +inline LinearCombination operator+(const LinearCombination& first, const LinearTerm& second) {return second + first;} +inline Polynomial operator+(const Monomial& first, const LinearTerm& second) {return second + first;} +inline Polynomial operator+(const Polynomial& first, const LinearTerm& second) {return second + first;} +inline LinearCombination operator+(const LinearTerm& first, const Variable& second) {return second + first;} +inline LinearCombination operator+(const LinearCombination& first, const Variable& second) {return second + first;} +inline Polynomial operator+(const Monomial& first, const Variable& second) {return second + first;} +inline Polynomial operator+(const Polynomial& first, const Variable& second) {return second + first;} +inline LinearCombination operator+(const Variable& first, const FElem& second) {return second + first;} +inline LinearCombination operator+(const LinearTerm& first, const FElem& second) {return second + first;} +inline LinearCombination operator+(const LinearCombination& first, const FElem& second) {return second + first;} +inline Polynomial operator+(const Monomial& first, const FElem& second) {return second + first;} +inline Polynomial operator+(const Polynomial& first, const FElem& second) {return second + first;} +inline FElem operator+(const FElem& first, const int second) {return second + first;} +inline LinearCombination operator+(const Variable& first, const int second) {return second + first;} +inline LinearCombination operator+(const LinearTerm& first, const int second) {return second + first;} +inline LinearCombination operator+(const LinearCombination& first, const int second) {return second + first;} +inline Polynomial operator+(const Monomial& first, const int second) {return second + first;} +inline Polynomial operator+(const Polynomial& first, const int second) {return second + first;} + +/***********************************/ +/*** operator- ***/ +/***********************************/ +inline LinearTerm operator-(const Variable& src) {return LinearTerm(src, -1);} + +inline Polynomial operator-(const Polynomial& first, const Polynomial& second) {return first + (-second);} +inline Polynomial operator-(const Monomial& first, const Polynomial& second) {return first + (-second);} +inline Polynomial operator-(const Monomial& first, const Monomial& second) {return first + (-second);} +inline Polynomial operator-(const LinearCombination& first, const Polynomial& second) {return first + (-second);} +inline Polynomial operator-(const LinearCombination& first, const Monomial& second) {return first + (-second);} +inline LinearCombination operator-(const LinearCombination& first, const LinearCombination& second) {return first + (-second);} +inline Polynomial operator-(const LinearTerm& first, const Polynomial& second) {return first + (-second);} +inline Polynomial operator-(const LinearTerm& first, const Monomial& second) {return first + (-second);} +inline LinearCombination operator-(const LinearTerm& first, const LinearCombination& second) {return first + (-second);} +inline LinearCombination operator-(const LinearTerm& first, const LinearTerm& second) {return first + (-second);} +inline Polynomial operator-(const Variable& first, const Polynomial& second) {return first + (-second);} +inline Polynomial operator-(const Variable& first, const Monomial& second) {return first + (-second);} +inline LinearCombination operator-(const Variable& first, const LinearCombination& second) {return first + (-second);} +inline LinearCombination operator-(const Variable& first, const LinearTerm& second) {return first + (-second);} +inline LinearCombination operator-(const Variable& first, const Variable& second) {return first + (-second);} +inline Polynomial operator-(const FElem& first, const Polynomial& second) {return first + (-second);} +inline Polynomial operator-(const FElem& first, const Monomial& second) {return first + (-second);} +inline LinearCombination operator-(const FElem& first, const LinearCombination& second) {return first + (-second);} +inline LinearCombination operator-(const FElem& first, const LinearTerm& second) {return first + (-second);} +inline LinearCombination operator-(const FElem& first, const Variable& second) {return first + (-second);} +inline FElem operator-(const FElem& first, const FElem& second) {return first + (-second);} +inline FElem operator-(const int first, const FElem& second) {return first + (-second);} +inline LinearCombination operator-(const int first, const Variable& second) {return first + (-second);} +inline LinearCombination operator-(const int first, const LinearTerm& second) {return first + (-second);} +inline LinearCombination operator-(const int first, const LinearCombination& second) {return first + (-second);} +inline Polynomial operator-(const int first, const Monomial& second) {return first + (-second);} +inline Polynomial operator-(const int first, const Polynomial& second) {return first + (-second);} +inline Polynomial operator-(const Polynomial& first, const Monomial& second) {return first + (-second);} +inline Polynomial operator-(const Monomial& first, const LinearCombination& second) {return first + (-second);} +inline Polynomial operator-(const Polynomial& first, const LinearCombination& second) {return first + (-second);} +inline LinearCombination operator-(const LinearCombination& first, const LinearTerm& second) {return first + (-second);} +inline Polynomial operator-(const Monomial& first, const LinearTerm& second) {return first + (-second);} +inline Polynomial operator-(const Polynomial& first, const LinearTerm& second) {return first + (-second);} +inline LinearCombination operator-(const LinearTerm& first, const Variable& second) {return first + (-second);} +inline LinearCombination operator-(const LinearCombination& first, const Variable& second) {return first + (-second);} +inline Polynomial operator-(const Monomial& first, const Variable& second) {return first + (-second);} +inline Polynomial operator-(const Polynomial& first, const Variable& second) {return first + (-second);} +inline LinearCombination operator-(const Variable& first, const FElem& second) {return first + (-second);} +inline LinearCombination operator-(const LinearTerm& first, const FElem& second) {return first + (-second);} +inline LinearCombination operator-(const LinearCombination& first, const FElem& second) {return first + (-second);} +inline Polynomial operator-(const Monomial& first, const FElem& second) {return first + (-second);} +inline Polynomial operator-(const Polynomial& first, const FElem& second) {return first + (-second);} +inline FElem operator-(const FElem& first, const int second) {return first + (-second);} +inline LinearCombination operator-(const Variable& first, const int second) {return first + (-second);} +inline LinearCombination operator-(const LinearTerm& first, const int second) {return first + (-second);} +inline LinearCombination operator-(const LinearCombination& first, const int second) {return first + (-second);} +inline Polynomial operator-(const Monomial& first, const int second) {return first + (-second);} +inline Polynomial operator-(const Polynomial& first, const int second) {return first + (-second);} + +/***********************************/ +/*** operator* ***/ +/***********************************/ + +// Polynomial +inline Polynomial operator*(const Polynomial& first, const Polynomial& second) {auto retval = first; return retval *= second;} + +// Monomial +inline Polynomial operator*(const Monomial& first, const Polynomial& second) {return Polynomial(first) * second;} +inline Monomial operator*(const Monomial& first, const Monomial& second) {auto retval = first; return retval *= second;} + +// LinearCombination +inline Polynomial operator*(const LinearCombination& first, const Polynomial& second) {return Polynomial(first) * second;} +inline Polynomial operator*(const LinearCombination& first, const Monomial& second) {return first * Polynomial(second);} +inline Polynomial operator*(const LinearCombination& first, const LinearCombination& second) {return first * Polynomial(second);} + +// LinearTerm +inline Polynomial operator*(const LinearTerm& first, const Polynomial& second) {return LinearCombination(first) * second;} +inline Monomial operator*(const LinearTerm& first, const Monomial& second) {return Monomial(first) * second;} +inline Polynomial operator*(const LinearTerm& first, const LinearCombination& second) {return LinearCombination(first) * second;} +inline Monomial operator*(const LinearTerm& first, const LinearTerm& second) {return Monomial(first) * Monomial(second);} + +// Variable +inline Polynomial operator*(const Variable& first, const Polynomial& second) {return LinearTerm(first) * second;} +inline Monomial operator*(const Variable& first, const Monomial& second) {return Monomial(first) * second;} +inline Polynomial operator*(const Variable& first, const LinearCombination& second) {return LinearTerm(first) * second;} +inline Monomial operator*(const Variable& first, const LinearTerm& second) {return LinearTerm(first) * second;} +inline Monomial operator*(const Variable& first, const Variable& second) {return LinearTerm(first) * LinearTerm(second);} + +// FElem +inline Polynomial operator*(const FElem& first, const Polynomial& second) {return LinearCombination(first) * second;} +inline Monomial operator*(const FElem& first, const Monomial& second) {return Monomial(first) * second;} +inline LinearCombination operator*(const FElem& first, const LinearCombination& second) {auto retval = second; return retval *= first;} +inline LinearTerm operator*(const FElem& first, const LinearTerm& second) {auto retval = second; return retval *= first;} +inline LinearTerm operator*(const FElem& first, const Variable& second) {return LinearTerm(second) *= first;} +inline FElem operator*(const FElem& first, const FElem& second) {auto retval = first; return retval *= second;} + +// int +inline FElem operator*(const int first, const FElem& second) {return FElem(first) * second;} +inline LinearTerm operator*(const int first, const Variable& second) {return FElem(first) * second;} +inline LinearTerm operator*(const int first, const LinearTerm& second) {return FElem(first) * second;} +inline LinearCombination operator*(const int first, const LinearCombination& second) {return FElem(first) * second;} +inline Monomial operator*(const int first, const Monomial& second) {return FElem(first) * second;} +inline Polynomial operator*(const int first, const Polynomial& second) {return FElem(first) * second;} + +// symetrical operators +inline Polynomial operator*(const Polynomial& first, const Monomial& second) {return second * first;} +inline Polynomial operator*(const Monomial& first, const LinearCombination& second) {return second * first;} +inline Polynomial operator*(const Polynomial& first, const LinearCombination& second) {return second * first;} +inline Polynomial operator*(const LinearCombination& first, const LinearTerm& second) {return second * first;} +inline Monomial operator*(const Monomial& first, const LinearTerm& second) {return second * first;} +inline Polynomial operator*(const Polynomial& first, const LinearTerm& second) {return second * first;} +inline Monomial operator*(const LinearTerm& first, const Variable& second) {return second * first;} +inline Polynomial operator*(const LinearCombination& first, const Variable& second) {return second * first;} +inline Monomial operator*(const Monomial& first, const Variable& second) {return second * first;} +inline Polynomial operator*(const Polynomial& first, const Variable& second) {return second * first;} +inline LinearTerm operator*(const Variable& first, const FElem& second) {return second * first;} +inline LinearTerm operator*(const LinearTerm& first, const FElem& second) {return second * first;} +inline LinearCombination operator*(const LinearCombination& first, const FElem& second) {return second * first;} +inline Monomial operator*(const Monomial& first, const FElem& second) {return second * first;} +inline Polynomial operator*(const Polynomial& first, const FElem& second) {return second * first;} +inline FElem operator*(const FElem& first, const int second) {return second * first;} +inline LinearTerm operator*(const Variable& first, const int second) {return second * first;} +inline LinearTerm operator*(const LinearTerm& first, const int second) {return second * first;} +inline LinearCombination operator*(const LinearCombination& first, const int second) {return second * first;} +inline Monomial operator*(const Monomial& first, const int second) {return second * first;} +inline Polynomial operator*(const Polynomial& first, const int second) {return second * first;} + + +/***********************************/ +/*** END OF OPERATORS ***/ +/***********************************/ + +} // namespace gadgetlib2 + +#endif // LIBSNARK_GADGETLIB2_INCLUDE_GADGETLIB2_VARIABLEOPERATORS_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/reductions/bacs_to_r1cs/bacs_to_r1cs.hpp b/privacy/zsl/zsl/snark/libsnark/src/reductions/bacs_to_r1cs/bacs_to_r1cs.hpp new file mode 100644 index 0000000..87599ce --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/reductions/bacs_to_r1cs/bacs_to_r1cs.hpp @@ -0,0 +1,44 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for a BACS-to-R1CS reduction, that is, constructing + a R1CS ("Rank-1 Constraint System") from a BACS ("Bilinear Arithmetic Circuit Satisfiability"). + + The reduction is straightforward: each bilinear gate gives rises to a + corresponding R1CS constraint that enforces correct computation of the gate; + also, each output gives rise to a corresponding R1CS constraint that enforces + that the output is zero. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef BACS_TO_R1CS_HPP_ +#define BACS_TO_R1CS_HPP_ + +#include "relations/circuit_satisfaction_problems/bacs/bacs.hpp" +#include "relations/constraint_satisfaction_problems/r1cs/r1cs.hpp" + +namespace libsnark { + +/** + * Instance map for the BACS-to-R1CS reduction. + */ +template +r1cs_constraint_system bacs_to_r1cs_instance_map(const bacs_circuit &circuit); + +/** + * Witness map for the BACS-to-R1CS reduction. + */ +template +r1cs_variable_assignment bacs_to_r1cs_witness_map(const bacs_circuit &circuit, + const bacs_primary_input &primary_input, + const bacs_auxiliary_input &auxiliary_input); + +} // libsnark + +#include "reductions/bacs_to_r1cs/bacs_to_r1cs.tcc" + +#endif // BACS_TO_R1CS_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/reductions/bacs_to_r1cs/bacs_to_r1cs.tcc b/privacy/zsl/zsl/snark/libsnark/src/reductions/bacs_to_r1cs/bacs_to_r1cs.tcc new file mode 100644 index 0000000..45f78a7 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/reductions/bacs_to_r1cs/bacs_to_r1cs.tcc @@ -0,0 +1,79 @@ +/** @file +***************************************************************************** + +Implementation of interfaces for a BACS-to-R1CS reduction. + +See bacs_to_r1cs.hpp . + +***************************************************************************** +* @author This file is part of libsnark, developed by SCIPR Lab +* and contributors (see AUTHORS). +* @copyright MIT license (see LICENSE file) +*****************************************************************************/ + +#ifndef BACS_TO_R1CS_TCC_ +#define BACS_TO_R1CS_TCC_ + +#include "relations/circuit_satisfaction_problems/bacs/bacs.hpp" +#include "relations/constraint_satisfaction_problems/r1cs/r1cs.hpp" + +namespace libsnark { + +template +r1cs_constraint_system bacs_to_r1cs_instance_map(const bacs_circuit &circuit) +{ + enter_block("Call to bacs_to_r1cs_instance_map"); + assert(circuit.is_valid()); + r1cs_constraint_system result; + +#ifdef DEBUG + result.variable_annotations = circuit.variable_annotations; +#endif + + result.primary_input_size = circuit.primary_input_size; + result.auxiliary_input_size = circuit.auxiliary_input_size + circuit.gates.size(); + + for (auto &g : circuit.gates) + { + result.constraints.emplace_back(r1cs_constraint(g.lhs, g.rhs, g.output)); +#ifdef DEBUG + auto it = circuit.gate_annotations.find(g.output.index); + if (it != circuit.gate_annotations.end()) + { + result.constraint_annotations[result.constraints.size()-1] = it->second; + } +#endif + } + + for (auto &g : circuit.gates) + { + if (g.is_circuit_output) + { + result.constraints.emplace_back(r1cs_constraint(1, g.output, 0)); + +#ifdef DEBUG + result.constraint_annotations[result.constraints.size()-1] = FMT("", "output_%zu_is_circuit_output", g.output.index); +#endif + } + } + + leave_block("Call to bacs_to_r1cs_instance_map"); + + return result; +} + +template +r1cs_variable_assignment bacs_to_r1cs_witness_map(const bacs_circuit &circuit, + const bacs_primary_input &primary_input, + const bacs_auxiliary_input &auxiliary_input) +{ + enter_block("Call to bacs_to_r1cs_witness_map"); + const r1cs_variable_assignment result = circuit.get_all_wires(primary_input, auxiliary_input); + leave_block("Call to bacs_to_r1cs_witness_map"); + + return result; +} + +} // libsnark + +#endif // BACS_TO_R1CS_TCC_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/reductions/r1cs_to_qap/r1cs_to_qap.hpp b/privacy/zsl/zsl/snark/libsnark/src/reductions/r1cs_to_qap/r1cs_to_qap.hpp new file mode 100644 index 0000000..b3cde71 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/reductions/r1cs_to_qap/r1cs_to_qap.hpp @@ -0,0 +1,70 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for a R1CS-to-QAP reduction, that is, constructing + a QAP ("Quadratic Arithmetic Program") from a R1CS ("Rank-1 Constraint System"). + + QAPs are defined in \[GGPR13], and construced for R1CS also in \[GGPR13]. + + The implementation of the reduction follows, extends, and optimizes + the efficient approach described in Appendix E of \[BCGTV13]. + + References: + + \[BCGTV13] + "SNARKs for C: Verifying Program Executions Succinctly and in Zero Knowledge", + Eli Ben-Sasson, Alessandro Chiesa, Daniel Genkin, Eran Tromer, Madars Virza, + CRYPTO 2013, + + + \[GGPR13]: + "Quadratic span programs and succinct NIZKs without PCPs", + Rosario Gennaro, Craig Gentry, Bryan Parno, Mariana Raykova, + EUROCRYPT 2013, + + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef R1CS_TO_QAP_HPP_ +#define R1CS_TO_QAP_HPP_ + +#include "relations/arithmetic_programs/qap/qap.hpp" +#include "relations/constraint_satisfaction_problems/r1cs/r1cs.hpp" + +namespace libsnark { + +/** + * Instance map for the R1CS-to-QAP reduction. + */ +template +qap_instance r1cs_to_qap_instance_map(const r1cs_constraint_system &cs); + +/** + * Instance map for the R1CS-to-QAP reduction followed by evaluation of the resulting QAP instance. + */ +template +qap_instance_evaluation r1cs_to_qap_instance_map_with_evaluation(const r1cs_constraint_system &cs, + const FieldT &t); + +/** + * Witness map for the R1CS-to-QAP reduction. + * + * The witness map takes zero knowledge into account when d1,d2,d3 are random. + */ +template +qap_witness r1cs_to_qap_witness_map(const r1cs_constraint_system &cs, + const r1cs_primary_input &primary_input, + const r1cs_auxiliary_input &auxiliary_input, + const FieldT &d1, + const FieldT &d2, + const FieldT &d3); + +} // libsnark + +#include "reductions/r1cs_to_qap/r1cs_to_qap.tcc" + +#endif // R1CS_TO_QAP_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/reductions/r1cs_to_qap/r1cs_to_qap.tcc b/privacy/zsl/zsl/snark/libsnark/src/reductions/r1cs_to_qap/r1cs_to_qap.tcc new file mode 100644 index 0000000..3d0bee2 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/reductions/r1cs_to_qap/r1cs_to_qap.tcc @@ -0,0 +1,338 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for a R1CS-to-QAP reduction. + + See r1cs_to_qap.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef R1CS_TO_QAP_TCC_ +#define R1CS_TO_QAP_TCC_ + +#include "common/profiling.hpp" +#include "common/utils.hpp" +#include "algebra/evaluation_domain/evaluation_domain.hpp" + +namespace libsnark { + +/** + * Instance map for the R1CS-to-QAP reduction. + * + * Namely, given a R1CS constraint system cs, construct a QAP instance for which: + * A := (A_0(z),A_1(z),...,A_m(z)) + * B := (B_0(z),B_1(z),...,B_m(z)) + * C := (C_0(z),C_1(z),...,C_m(z)) + * where + * m = number of variables of the QAP + * and + * each A_i,B_i,C_i is expressed in the Lagrange basis. + */ +template +qap_instance r1cs_to_qap_instance_map(const r1cs_constraint_system &cs) +{ + enter_block("Call to r1cs_to_qap_instance_map"); + + const std::shared_ptr > domain = get_evaluation_domain(cs.num_constraints() + cs.num_inputs() + 1); + + std::vector > A_in_Lagrange_basis(cs.num_variables()+1); + std::vector > B_in_Lagrange_basis(cs.num_variables()+1); + std::vector > C_in_Lagrange_basis(cs.num_variables()+1); + + enter_block("Compute polynomials A, B, C in Lagrange basis"); + /** + * add and process the constraints + * input_i * 0 = 0 + * to ensure soundness of input consistency + */ + for (size_t i = 0; i <= cs.num_inputs(); ++i) + { + A_in_Lagrange_basis[i][cs.num_constraints() + i] = FieldT::one(); + } + /* process all other constraints */ + for (size_t i = 0; i < cs.num_constraints(); ++i) + { + for (size_t j = 0; j < cs.constraints[i].a.terms.size(); ++j) + { + A_in_Lagrange_basis[cs.constraints[i].a.terms[j].index][i] += + cs.constraints[i].a.terms[j].coeff; + } + + for (size_t j = 0; j < cs.constraints[i].b.terms.size(); ++j) + { + B_in_Lagrange_basis[cs.constraints[i].b.terms[j].index][i] += + cs.constraints[i].b.terms[j].coeff; + } + + for (size_t j = 0; j < cs.constraints[i].c.terms.size(); ++j) + { + C_in_Lagrange_basis[cs.constraints[i].c.terms[j].index][i] += + cs.constraints[i].c.terms[j].coeff; + } + } + leave_block("Compute polynomials A, B, C in Lagrange basis"); + + leave_block("Call to r1cs_to_qap_instance_map"); + + return qap_instance(domain, + cs.num_variables(), + domain->m, + cs.num_inputs(), + std::move(A_in_Lagrange_basis), + std::move(B_in_Lagrange_basis), + std::move(C_in_Lagrange_basis)); +} + +/** + * Instance map for the R1CS-to-QAP reduction followed by evaluation of the resulting QAP instance. + * + * Namely, given a R1CS constraint system cs and a field element t, construct + * a QAP instance (evaluated at t) for which: + * At := (A_0(t),A_1(t),...,A_m(t)) + * Bt := (B_0(t),B_1(t),...,B_m(t)) + * Ct := (C_0(t),C_1(t),...,C_m(t)) + * Ht := (1,t,t^2,...,t^n) + * Zt := Z(t) = "vanishing polynomial of a certain set S, evaluated at t" + * where + * m = number of variables of the QAP + * n = degree of the QAP + */ +template +qap_instance_evaluation r1cs_to_qap_instance_map_with_evaluation(const r1cs_constraint_system &cs, + const FieldT &t) +{ + enter_block("Call to r1cs_to_qap_instance_map_with_evaluation"); + + const std::shared_ptr > domain = get_evaluation_domain(cs.num_constraints() + cs.num_inputs() + 1); + + std::vector At, Bt, Ct, Ht; + + At.resize(cs.num_variables()+1, FieldT::zero()); + Bt.resize(cs.num_variables()+1, FieldT::zero()); + Ct.resize(cs.num_variables()+1, FieldT::zero()); + Ht.reserve(domain->m+1); + + const FieldT Zt = domain->compute_Z(t); + + enter_block("Compute evaluations of A, B, C, H at t"); + const std::vector u = domain->lagrange_coeffs(t); + /** + * add and process the constraints + * input_i * 0 = 0 + * to ensure soundness of input consistency + */ + for (size_t i = 0; i <= cs.num_inputs(); ++i) + { + At[i] = u[cs.num_constraints() + i]; + } + /* process all other constraints */ + for (size_t i = 0; i < cs.num_constraints(); ++i) + { + for (size_t j = 0; j < cs.constraints[i].a.terms.size(); ++j) + { + At[cs.constraints[i].a.terms[j].index] += + u[i]*cs.constraints[i].a.terms[j].coeff; + } + + for (size_t j = 0; j < cs.constraints[i].b.terms.size(); ++j) + { + Bt[cs.constraints[i].b.terms[j].index] += + u[i]*cs.constraints[i].b.terms[j].coeff; + } + + for (size_t j = 0; j < cs.constraints[i].c.terms.size(); ++j) + { + Ct[cs.constraints[i].c.terms[j].index] += + u[i]*cs.constraints[i].c.terms[j].coeff; + } + } + + FieldT ti = FieldT::one(); + for (size_t i = 0; i < domain->m+1; ++i) + { + Ht.emplace_back(ti); + ti *= t; + } + leave_block("Compute evaluations of A, B, C, H at t"); + + leave_block("Call to r1cs_to_qap_instance_map_with_evaluation"); + + return qap_instance_evaluation(domain, + cs.num_variables(), + domain->m, + cs.num_inputs(), + t, + std::move(At), + std::move(Bt), + std::move(Ct), + std::move(Ht), + Zt); +} + +/** + * Witness map for the R1CS-to-QAP reduction. + * + * The witness map takes zero knowledge into account when d1,d2,d3 are random. + * + * More precisely, compute the coefficients + * h_0,h_1,...,h_n + * of the polynomial + * H(z) := (A(z)*B(z)-C(z))/Z(z) + * where + * A(z) := A_0(z) + \sum_{k=1}^{m} w_k A_k(z) + d1 * Z(z) + * B(z) := B_0(z) + \sum_{k=1}^{m} w_k B_k(z) + d2 * Z(z) + * C(z) := C_0(z) + \sum_{k=1}^{m} w_k C_k(z) + d3 * Z(z) + * Z(z) := "vanishing polynomial of set S" + * and + * m = number of variables of the QAP + * n = degree of the QAP + * + * This is done as follows: + * (1) compute evaluations of A,B,C on S = {sigma_1,...,sigma_n} + * (2) compute coefficients of A,B,C + * (3) compute evaluations of A,B,C on T = "coset of S" + * (4) compute evaluation of H on T + * (5) compute coefficients of H + * (6) patch H to account for d1,d2,d3 (i.e., add coefficients of the polynomial (A d2 + B d1 - d3) + d1*d2*Z ) + * + * The code below is not as simple as the above high-level description due to + * some reshuffling to save space. + */ +template +qap_witness r1cs_to_qap_witness_map(const r1cs_constraint_system &cs, + const r1cs_primary_input &primary_input, + const r1cs_auxiliary_input &auxiliary_input, + const FieldT &d1, + const FieldT &d2, + const FieldT &d3) +{ + enter_block("Call to r1cs_to_qap_witness_map"); + + /* sanity check */ + assert(cs.is_satisfied(primary_input, auxiliary_input)); + + const std::shared_ptr > domain = get_evaluation_domain(cs.num_constraints() + cs.num_inputs() + 1); + + r1cs_variable_assignment full_variable_assignment = primary_input; + full_variable_assignment.insert(full_variable_assignment.end(), auxiliary_input.begin(), auxiliary_input.end()); + + enter_block("Compute evaluation of polynomials A, B on set S"); + std::vector aA(domain->m, FieldT::zero()), aB(domain->m, FieldT::zero()); + + /* account for the additional constraints input_i * 0 = 0 */ + for (size_t i = 0; i <= cs.num_inputs(); ++i) + { + aA[i+cs.num_constraints()] = (i > 0 ? full_variable_assignment[i-1] : FieldT::one()); + } + /* account for all other constraints */ + for (size_t i = 0; i < cs.num_constraints(); ++i) + { + aA[i] += cs.constraints[i].a.evaluate(full_variable_assignment); + aB[i] += cs.constraints[i].b.evaluate(full_variable_assignment); + } + leave_block("Compute evaluation of polynomials A, B on set S"); + + enter_block("Compute coefficients of polynomial A"); + domain->iFFT(aA); + leave_block("Compute coefficients of polynomial A"); + + enter_block("Compute coefficients of polynomial B"); + domain->iFFT(aB); + leave_block("Compute coefficients of polynomial B"); + + enter_block("Compute ZK-patch"); + std::vector coefficients_for_H(domain->m+1, FieldT::zero()); +#ifdef MULTICORE +#pragma omp parallel for +#endif + /* add coefficients of the polynomial (d2*A + d1*B - d3) + d1*d2*Z */ + for (size_t i = 0; i < domain->m; ++i) + { + coefficients_for_H[i] = d2*aA[i] + d1*aB[i]; + } + coefficients_for_H[0] -= d3; + domain->add_poly_Z(d1*d2, coefficients_for_H); + leave_block("Compute ZK-patch"); + + enter_block("Compute evaluation of polynomial A on set T"); + domain->cosetFFT(aA, FieldT::multiplicative_generator); + leave_block("Compute evaluation of polynomial A on set T"); + + enter_block("Compute evaluation of polynomial B on set T"); + domain->cosetFFT(aB, FieldT::multiplicative_generator); + leave_block("Compute evaluation of polynomial B on set T"); + + enter_block("Compute evaluation of polynomial H on set T"); + std::vector &H_tmp = aA; // can overwrite aA because it is not used later +#ifdef MULTICORE +#pragma omp parallel for +#endif + for (size_t i = 0; i < domain->m; ++i) + { + H_tmp[i] = aA[i]*aB[i]; + } + std::vector().swap(aB); // destroy aB + + enter_block("Compute evaluation of polynomial C on set S"); + std::vector aC(domain->m, FieldT::zero()); + for (size_t i = 0; i < cs.num_constraints(); ++i) + { + aC[i] += cs.constraints[i].c.evaluate(full_variable_assignment); + } + leave_block("Compute evaluation of polynomial C on set S"); + + enter_block("Compute coefficients of polynomial C"); + domain->iFFT(aC); + leave_block("Compute coefficients of polynomial C"); + + enter_block("Compute evaluation of polynomial C on set T"); + domain->cosetFFT(aC, FieldT::multiplicative_generator); + leave_block("Compute evaluation of polynomial C on set T"); + +#ifdef MULTICORE +#pragma omp parallel for +#endif + for (size_t i = 0; i < domain->m; ++i) + { + H_tmp[i] = (H_tmp[i]-aC[i]); + } + + enter_block("Divide by Z on set T"); + domain->divide_by_Z_on_coset(H_tmp); + leave_block("Divide by Z on set T"); + + leave_block("Compute evaluation of polynomial H on set T"); + + enter_block("Compute coefficients of polynomial H"); + domain->icosetFFT(H_tmp, FieldT::multiplicative_generator); + leave_block("Compute coefficients of polynomial H"); + + enter_block("Compute sum of H and ZK-patch"); +#ifdef MULTICORE +#pragma omp parallel for +#endif + for (size_t i = 0; i < domain->m; ++i) + { + coefficients_for_H[i] += H_tmp[i]; + } + leave_block("Compute sum of H and ZK-patch"); + + leave_block("Call to r1cs_to_qap_witness_map"); + + return qap_witness(cs.num_variables(), + domain->m, + cs.num_inputs(), + d1, + d2, + d3, + full_variable_assignment, + std::move(coefficients_for_H)); +} + +} // libsnark + +#endif // R1CS_TO_QAP_TCC_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/reductions/ram_to_r1cs/examples/demo_arithmetization.cpp b/privacy/zsl/zsl/snark/libsnark/src/reductions/ram_to_r1cs/examples/demo_arithmetization.cpp new file mode 100644 index 0000000..1698301 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/reductions/ram_to_r1cs/examples/demo_arithmetization.cpp @@ -0,0 +1,144 @@ +/** + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ +#include +#include +#include +#include +#include +#ifndef MINDEPS +#include +#endif + +#include "common/default_types/tinyram_ppzksnark_pp.hpp" +#include "common/profiling.hpp" +#include "reductions/ram_to_r1cs/ram_to_r1cs.hpp" +#include "relations/ram_computations/rams/tinyram/tinyram_params.hpp" +#include "zk_proof_systems/ppzksnark/ram_ppzksnark/ram_ppzksnark.hpp" + +#ifndef MINDEPS +namespace po = boost::program_options; + +bool process_arithm_command_line(const int argc, const char** argv, + std::string &assembly_fn, + std::string &processed_assembly_fn, + std::string &architecture_params_fn, + std::string &computation_bounds_fn, + std::string &primary_input_fn, + std::string &auxiliary_input_fn) +{ + try + { + po::options_description desc("Usage"); + desc.add_options() + ("help", "print this help message") + ("assembly", po::value(&assembly_fn)->required()) + ("processed_assembly", po::value(&processed_assembly_fn)->required()) + ("architecture_params", po::value(&architecture_params_fn)->required()) + ("computation_bounds", po::value(&computation_bounds_fn)->required()) + ("primary_input", po::value(&primary_input_fn)->required()) + ("auxiliary_input", po::value(&auxiliary_input_fn)->required()); + + po::variables_map vm; + po::store(po::parse_command_line(argc, argv, desc), vm); + + if (vm.count("help")) + { + std::cout << desc << "\n"; + return false; + } + + po::notify(vm); + } + catch(std::exception& e) + { + std::cerr << "Error: " << e.what() << "\n"; + return false; + } + + return true; +} +#endif + +using namespace libsnark; + +int main(int argc, const char * argv[]) +{ + typedef Fr FieldT; + typedef ram_tinyram default_ram; + + default_ec_pp::init_public_params(); + +#ifdef MINDEPS + std::string assembly_fn = "assembly.s"; + std::string processed_assembly_fn = "processed.txt"; + std::string architecture_params_fn = "architecture_params.txt"; + std::string computation_bounds_fn = "computation_bounds.txt"; + std::string primary_input_fn = "primary_input.txt"; + std::string auxiliary_input_fn = "auxiliary_input.txt"; +#else + std::string assembly_fn; + std::string processed_assembly_fn; + std::string architecture_params_fn; + std::string computation_bounds_fn; + std::string primary_input_fn; + std::string auxiliary_input_fn; + + if (!process_arithm_command_line(argc, argv, assembly_fn, processed_assembly_fn, architecture_params_fn, + computation_bounds_fn, primary_input_fn, auxiliary_input_fn)) + { + return 1; + } +#endif + start_profiling(); + + printf("================================================================================\n"); + printf("TinyRAM example loader\n"); + printf("================================================================================\n\n"); + + /* load everything */ + ram_architecture_params ap; + std::ifstream f_ap(architecture_params_fn); + f_ap >> ap; + + printf("Will run on %zu register machine (word size = %zu)\n", ap.k, ap.w); + + std::ifstream f_rp(computation_bounds_fn); + size_t tinyram_input_size_bound, tinyram_program_size_bound, time_bound; + f_rp >> tinyram_input_size_bound >> tinyram_program_size_bound >> time_bound; + + std::ifstream processed(processed_assembly_fn); + std::ifstream raw(assembly_fn); + tinyram_program program = load_preprocessed_program(ap, processed); + printf("Program:\n%s\n", std::string((std::istreambuf_iterator(raw)), + std::istreambuf_iterator()).c_str()); + + std::ifstream f_primary_input(primary_input_fn); + std::ifstream f_auxiliary_input(auxiliary_input_fn); + + enter_block("Loading primary input"); + tinyram_input_tape primary_input(load_tape(f_primary_input)); + leave_block("Loading primary input"); + + enter_block("Loading auxiliary input"); + tinyram_input_tape auxiliary_input = load_tape(f_auxiliary_input); + leave_block("Loading auxiliary input"); + + const size_t boot_trace_size_bound = tinyram_input_size_bound + tinyram_program_size_bound; + const ram_boot_trace boot_trace = tinyram_boot_trace_from_program_and_input(ap, boot_trace_size_bound, program, primary_input); + + typedef ram_ppzksnark_machine_pp default_ram; + + ram_to_r1cs r(ap, boot_trace_size_bound, time_bound); + r.instance_map(); + + const r1cs_primary_input r1cs_primary_input = ram_to_r1cs::primary_input_map(ap, boot_trace_size_bound, boot_trace); + const r1cs_auxiliary_input r1cs_auxiliary_input = r.auxiliary_input_map(boot_trace, auxiliary_input); + const r1cs_constraint_system constraint_system = r.get_constraint_system(); + + r.print_execution_trace(); + assert(constraint_system.is_satisfied(r1cs_primary_input, r1cs_auxiliary_input)); +} diff --git a/privacy/zsl/zsl/snark/libsnark/src/reductions/ram_to_r1cs/gadgets/memory_checker_gadget.hpp b/privacy/zsl/zsl/snark/libsnark/src/reductions/ram_to_r1cs/gadgets/memory_checker_gadget.hpp new file mode 100644 index 0000000..7ec8fcd --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/reductions/ram_to_r1cs/gadgets/memory_checker_gadget.hpp @@ -0,0 +1,58 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for memory_checker_gadget, a gadget that verifies the + consistency of two accesses to memory that are adjacent in a "memory sort". + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef MEMORY_CHECKER_GADGET_HPP_ +#define MEMORY_CHECKER_GADGET_HPP_ + +#include "reductions/ram_to_r1cs/gadgets/trace_lines.hpp" + +namespace libsnark { + +template +class memory_checker_gadget : public ram_gadget_base { +private: + + typedef ram_base_field FieldT; + + pb_variable timestamps_leq; + pb_variable timestamps_less; + std::shared_ptr > compare_timestamps; + + pb_variable addresses_eq; + pb_variable addresses_leq; + pb_variable addresses_less; + std::shared_ptr > compare_addresses; + + pb_variable loose_contents_after1_equals_contents_before2; + pb_variable loose_contents_before2_equals_zero; + pb_variable loose_timestamp2_is_zero; + +public: + + memory_line_variable_gadget line1; + memory_line_variable_gadget line2; + + memory_checker_gadget(ram_protoboard &pb, + const size_t timestamp_size, + const memory_line_variable_gadget &line1, + const memory_line_variable_gadget &line2, + const std::string& annotation_prefix=""); + + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + +} // libsnark + +#include "reductions/ram_to_r1cs/gadgets/memory_checker_gadget.tcc" + +#endif // MEMORY_CHECKER_GADGET_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/reductions/ram_to_r1cs/gadgets/memory_checker_gadget.tcc b/privacy/zsl/zsl/snark/libsnark/src/reductions/ram_to_r1cs/gadgets/memory_checker_gadget.tcc new file mode 100644 index 0000000..f302d44 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/reductions/ram_to_r1cs/gadgets/memory_checker_gadget.tcc @@ -0,0 +1,134 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for memory_checker_gadget. + + See memory_checker_gadget.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef MEMORY_CHECKER_GADGET_TCC_ +#define MEMORY_CHECKER_GADGET_TCC_ + +namespace libsnark { + +template +memory_checker_gadget::memory_checker_gadget(ram_protoboard &pb, + const size_t timestamp_size, + const memory_line_variable_gadget &line1, + const memory_line_variable_gadget &line2, + const std::string& annotation_prefix) : + ram_gadget_base(pb, annotation_prefix), line1(line1), line2(line2) +{ + /* compare the two timestamps */ + timestamps_leq.allocate(pb, FMT(this->annotation_prefix, " timestamps_leq")); + timestamps_less.allocate(pb, FMT(this->annotation_prefix, " timestamps_less")); + compare_timestamps.reset(new comparison_gadget(pb, timestamp_size, line1.timestamp->packed, line2.timestamp->packed, timestamps_less, timestamps_leq, + FMT(this->annotation_prefix, " compare_ts"))); + + + /* compare the two addresses */ + const size_t address_size = pb.ap.address_size(); + addresses_eq.allocate(pb, FMT(this->annotation_prefix, " addresses_eq")); + addresses_leq.allocate(pb, FMT(this->annotation_prefix, " addresses_leq")); + addresses_less.allocate(pb, FMT(this->annotation_prefix, " addresses_less")); + compare_addresses.reset(new comparison_gadget(pb, address_size, line1.address->packed, line2.address->packed, addresses_less, addresses_leq, + FMT(this->annotation_prefix, " compare_addresses"))); + + /* + Add variables that will contain flags representing the following relations: + - "line1.contents_after = line2.contents_before" (to check that contents do not change between instructions); + - "line2.contents_before = 0" (for the first access at an address); and + - "line2.timestamp = 0" (for wrap-around checks to ensure only one 'cycle' in the memory sort). + + More precisely, each of the above flags is "loose" (i.e., it equals 0 if + the relation holds, but can be either 0 or 1 if the relation does not hold). + */ + loose_contents_after1_equals_contents_before2.allocate(pb, FMT(this->annotation_prefix, " loose_contents_after1_equals_contents_before2")); + loose_contents_before2_equals_zero.allocate(pb, FMT(this->annotation_prefix, " loose_contents_before2_equals_zero")); + loose_timestamp2_is_zero.allocate(pb, FMT(this->annotation_prefix, " loose_timestamp2_is_zero")); +} + +template +void memory_checker_gadget::generate_r1cs_constraints() +{ + /* compare the two timestamps */ + compare_timestamps->generate_r1cs_constraints(); + + /* compare the two addresses */ + compare_addresses->generate_r1cs_constraints(); + this->pb.add_r1cs_constraint(r1cs_constraint(addresses_leq, 1 - addresses_less, addresses_eq), FMT(this->annotation_prefix, " addresses_eq")); + + /* + Add constraints for the following three flags: + - loose_contents_after1_equals_contents_before2; + - loose_contents_before2_equals_zero; + - loose_timestamp2_is_zero. + */ + this->pb.add_r1cs_constraint(r1cs_constraint(loose_contents_after1_equals_contents_before2, + line1.contents_after->packed - line2.contents_before->packed, 0), + FMT(this->annotation_prefix, " loose_contents_after1_equals_contents_before2")); + generate_boolean_r1cs_constraint(this->pb, loose_contents_after1_equals_contents_before2, FMT(this->annotation_prefix, " loose_contents_after1_equals_contents_before2")); + + this->pb.add_r1cs_constraint(r1cs_constraint(loose_contents_before2_equals_zero, + line2.contents_before->packed, 0), + FMT(this->annotation_prefix, " loose_contents_before2_equals_zero")); + generate_boolean_r1cs_constraint(this->pb, loose_contents_before2_equals_zero, FMT(this->annotation_prefix, " loose_contents_before2_equals_zero")); + + this->pb.add_r1cs_constraint(r1cs_constraint(loose_timestamp2_is_zero, + line2.timestamp->packed, 0), + FMT(this->annotation_prefix, " loose_timestamp2_is_zero")); + generate_boolean_r1cs_constraint(this->pb, loose_timestamp2_is_zero, FMT(this->annotation_prefix, " loose_timestamp2_is_zero")); + + /* + The three cases that need to be checked are: + + line1.address = line2.address => line1.contents_after = line2.contents_before + (i.e. contents do not change between accesses to the same address) + + line1.address < line2.address => line2.contents_before = 0 + (i.e. access to new address has the "before" value set to 0) + + line1.address > line2.address => line2.timestamp = 0 + (i.e. there is only one cycle with non-decreasing addresses, except + for the case where we go back to a unique pre-set timestamp; we choose + timestamp 0 to be the one that touches address 0) + + As usual, we implement "A => B" as "NOT (A AND (NOT B))". + */ + this->pb.add_r1cs_constraint(r1cs_constraint(addresses_eq, 1 - loose_contents_after1_equals_contents_before2, 0), + FMT(this->annotation_prefix, " memory_retains_contents_between_accesses")); + this->pb.add_r1cs_constraint(r1cs_constraint(addresses_less, 1 - loose_contents_before2_equals_zero, 0), + FMT(this->annotation_prefix, " new_address_starts_at_zero")); + this->pb.add_r1cs_constraint(r1cs_constraint(1 - addresses_leq, 1 - loose_timestamp2_is_zero, 0), + FMT(this->annotation_prefix, " only_one_cycle")); +} + +template +void memory_checker_gadget::generate_r1cs_witness() +{ + /* compare the two addresses */ + compare_addresses->generate_r1cs_witness(); + this->pb.val(addresses_eq) = this->pb.val(addresses_leq) * (FieldT::one() - this->pb.val(addresses_less)); + + /* compare the two timestamps */ + compare_timestamps->generate_r1cs_witness(); + + /* + compare the values of: + - loose_contents_after1_equals_contents_before2; + - loose_contents_before2_equals_zero; + - loose_timestamp2_is_zero. + */ + this->pb.val(loose_contents_after1_equals_contents_before2) = (this->pb.val(line1.contents_after->packed) == this->pb.val(line2.contents_before->packed)) ? FieldT::one() : FieldT::zero(); + this->pb.val(loose_contents_before2_equals_zero) = this->pb.val(line2.contents_before->packed).is_zero() ? FieldT::one() : FieldT::zero(); + this->pb.val(loose_timestamp2_is_zero) = (this->pb.val(line2.timestamp->packed) == FieldT::zero() ? FieldT::one() : FieldT::zero()); +} + +} // libsnark + +#endif // MEMORY_CHECKER_GADGET_TCC_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/reductions/ram_to_r1cs/gadgets/ram_universal_gadget.hpp b/privacy/zsl/zsl/snark/libsnark/src/reductions/ram_to_r1cs/gadgets/ram_universal_gadget.hpp new file mode 100644 index 0000000..c6d05c2 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/reductions/ram_to_r1cs/gadgets/ram_universal_gadget.hpp @@ -0,0 +1,138 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for ram_universal_gadget. + + Given bounds on a RAM computation size (program size bound, primary input + size bound, and time bound), the "RAM universal gadget" checks the correct + execution of any RAM computation that fits the bounds. + + The implementaiton follows, extends, and optimizes the approach described + in \[BCTV14] (itself building on \[BCGTV13]). The code is parameterized by + the template parameter ramT, in order to support any RAM that fits certain + abstract interfaces. + + Roughly, the gadget has three main components: + - For each time step, a copy of a *execution checker* (which is the RAM CPU checker). + - For each time step, a copy of a *memory checker* (which verifies memory consitency + between two 'memory lines' that are adjacent in a memory sort). + - A single *routing network* (specifically, an arbitrary-size Waksman network), + which is used check that memory accesses are permutated according to some permutation. + + References: + + \[BCGTV13]: + "SNARKs for C: verifying program executions succinctly and in zero knowledge", + Eli Ben-Sasson, Alessandro Chiesa, Daniel Genkin, Eran Tromer, Madars Virza, + CRYPTO 2014, + + + \[BCTV14]: + "Succinct Non-Interactive Zero Knowledge for a von Neumann Architecture", + Eli Ben-Sasson, Alessandro Chiesa, Eran Tromer, Madars Virza, + USENIX Security 2014, + + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef RAM_UNIVERSAL_GADGET_HPP_ +#define RAM_UNIVERSAL_GADGET_HPP_ + +#include "gadgetlib1/gadgets/routing/as_waksman_routing_gadget.hpp" +#include "reductions/ram_to_r1cs/gadgets/memory_checker_gadget.hpp" +#include "reductions/ram_to_r1cs/gadgets/trace_lines.hpp" +#include "relations/ram_computations/rams/ram_params.hpp" + +namespace libsnark { + +/* + Memory layout for our reduction is as follows: + + (1) An initial execution line carrying the initial state (set + to all zeros) + (2) program_size_bound + primary_input_size_bound memory lines for + storing input and program (boot) + (3) time_bound pairs for (fetch instruction memory line, execute + instruction execution line) + + Memory line stores address, previous value and the next value of the + memory cell specified by the address. An execution line additionally + carries the CPU state. + + Our memory handling technique has a technical requirement that + address 0 must be accessed. We fulfill this by requiring the initial + execution line to act as "store 0 to address 0". + + --- + + As an implementation detail if less than program_size_bound + + primary_input_size_bound are used in the initial memory map, then we + pre-pend (!) them with "store 0 to address 0" lines. This + pre-pending means that memory maps that have non-zero value at + address 0 will still be handled correctly. + + The R1CS input packs the memory map starting from the last entry to + the first. This way, the prepended zeros arrive at the end of R1CS + input and thus can be ignored by the "weak" input consistency R1CS + verifier. +*/ + +template +class ram_universal_gadget : public ram_gadget_base { +public: + typedef ram_base_field FieldT; + + size_t num_memory_lines; + + std::vector > boot_lines; + std::vector > boot_line_bits; + std::vector > unpack_boot_lines; + + std::vector > load_instruction_lines; + std::vector > execution_lines; /* including the initial execution line */ + + std::vector* > unrouted_memory_lines; + std::vector > routed_memory_lines; + + std::vector > execution_checkers; + std::vector > memory_checkers; + + std::vector > routing_inputs; + std::vector > routing_outputs; + + std::shared_ptr > routing_network; + +public: + + size_t boot_trace_size_bound; + size_t time_bound; + pb_variable_array packed_input; + + ram_universal_gadget(ram_protoboard &pb, + const size_t boot_trace_size_bound, + const size_t time_bound, + const pb_variable_array &packed_input, + const std::string &annotation_prefix=""); + + void generate_r1cs_constraints(); + void generate_r1cs_witness(const ram_boot_trace &boot_trace, + const ram_input_tape &auxiliary_input); + + /* both methods assume that generate_r1cs_witness has been called */ + void print_execution_trace() const; + void print_memory_trace() const; + + static size_t packed_input_element_size(const ram_architecture_params &ap); + static size_t packed_input_size(const ram_architecture_params &ap, + const size_t boot_trace_size_bound); +}; + +} // libsnark + +#include "reductions/ram_to_r1cs/gadgets/ram_universal_gadget.tcc" + +#endif // RAM_UNIVERSAL_GADGET_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/reductions/ram_to_r1cs/gadgets/ram_universal_gadget.tcc b/privacy/zsl/zsl/snark/libsnark/src/reductions/ram_to_r1cs/gadgets/ram_universal_gadget.tcc new file mode 100644 index 0000000..00d2333 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/reductions/ram_to_r1cs/gadgets/ram_universal_gadget.tcc @@ -0,0 +1,433 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for ram_universal_gadget. + + See ram_universal_gadget.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef RAM_UNIVERSAL_GADGET_TCC_ +#define RAM_UNIVERSAL_GADGET_TCC_ + +#include "common/data_structures/integer_permutation.hpp" +#include "common/profiling.hpp" +#include "common/utils.hpp" +#include "algebra/fields/field_utils.hpp" +#include "relations/ram_computations/memory/ra_memory.hpp" + +namespace libsnark { + +template +ram_universal_gadget::ram_universal_gadget(ram_protoboard &pb, + const size_t boot_trace_size_bound, + const size_t time_bound, + const pb_variable_array &packed_input, + const std::string &annotation_prefix) : + ram_gadget_base(pb, annotation_prefix), + boot_trace_size_bound(boot_trace_size_bound), + time_bound(time_bound), + packed_input(packed_input) +{ + num_memory_lines = boot_trace_size_bound + (time_bound + 1) + time_bound; /* boot lines, (time_bound + 1) execution lines (including initial) and time_bound load instruction lines */ + const size_t timestamp_size = log2(num_memory_lines); + + /* allocate all lines on the execution side of the routing network */ + enter_block("Allocate initial state line"); + execution_lines.reserve(1 + time_bound); + execution_lines.emplace_back(execution_line_variable_gadget(pb, timestamp_size, pb.ap, FMT(annotation_prefix, " execution_lines_%zu", 0))); + unrouted_memory_lines.emplace_back(&execution_lines[0]); + leave_block("Allocate initial state line"); + + enter_block("Allocate boot lines"); + boot_lines.reserve(boot_trace_size_bound); + for (size_t i = 0; i < boot_trace_size_bound; ++i) + { + boot_lines.emplace_back(memory_line_variable_gadget(pb, timestamp_size, pb.ap, FMT(annotation_prefix, " boot_lines_%zu", i))); + unrouted_memory_lines.emplace_back(&boot_lines[i]); + } + leave_block("Allocate boot lines"); + + enter_block("Allocate instruction fetch and execution lines"); + load_instruction_lines.reserve(time_bound+1); /* the last line is NOT a memory line, but here just for uniform coding (i.e. the (unusued) result of next PC) */ + for (size_t i = 0; i < time_bound; ++i) + { + load_instruction_lines.emplace_back(memory_line_variable_gadget(pb, timestamp_size, pb.ap, FMT(annotation_prefix, " load_instruction_lines_%zu", i))); + unrouted_memory_lines.emplace_back(&load_instruction_lines[i]); + + execution_lines.emplace_back(execution_line_variable_gadget(pb, timestamp_size, pb.ap, FMT(annotation_prefix, " execution_lines_%zu", i+1))); + unrouted_memory_lines.emplace_back(&execution_lines[i+1]); + } + load_instruction_lines.emplace_back(memory_line_variable_gadget(pb, timestamp_size, pb.ap, FMT(annotation_prefix, " load_instruction_lines_%zu", time_bound))); + leave_block("Allocate instruction fetch and execution lines"); + + /* deal with packing of the input */ + enter_block("Pack input"); + const size_t line_size_bits = pb.ap.address_size() + pb.ap.value_size(); + const size_t max_chunk_size = FieldT::capacity(); + const size_t packed_line_size = div_ceil(line_size_bits, max_chunk_size); + assert(packed_input.size() == packed_line_size * boot_trace_size_bound); + + auto input_it = packed_input.begin(); + for (size_t i = 0; i < boot_trace_size_bound; ++i) + { + /* note the reversed order */ + pb_variable_array boot_line_bits; + boot_line_bits.insert(boot_line_bits.end(), boot_lines[boot_trace_size_bound-1-i].address->bits.begin(), boot_lines[boot_trace_size_bound-1-i].address->bits.end()); + boot_line_bits.insert(boot_line_bits.end(), boot_lines[boot_trace_size_bound-1-i].contents_after->bits.begin(), boot_lines[boot_trace_size_bound-1-i].contents_after->bits.end()); + + pb_variable_array packed_boot_line = pb_variable_array(input_it, input_it + packed_line_size); + std::advance(input_it, packed_line_size); + + unpack_boot_lines.emplace_back(multipacking_gadget(pb, boot_line_bits, packed_boot_line, max_chunk_size, FMT(annotation_prefix, " unpack_boot_lines_%zu", i))); + } + leave_block("Pack input"); + + /* deal with routing */ + enter_block("Allocate routed memory lines"); + for (size_t i = 0; i < num_memory_lines; ++i) + { + routed_memory_lines.emplace_back(memory_line_variable_gadget(pb, timestamp_size, pb.ap, FMT(annotation_prefix, " routed_memory_lines_%zu", i))); + } + leave_block("Allocate routed memory lines"); + + enter_block("Collect inputs/outputs for the routing network"); + routing_inputs.reserve(num_memory_lines); + routing_outputs.reserve(num_memory_lines); + + for (size_t i = 0; i < num_memory_lines; ++i) + { + routing_inputs.emplace_back(unrouted_memory_lines[i]->all_vars()); + routing_outputs.emplace_back(routed_memory_lines[i].all_vars()); + } + leave_block("Collect inputs/outputs for the routing network"); + + enter_block("Allocate routing network"); + routing_network.reset(new as_waksman_routing_gadget(pb, num_memory_lines, routing_inputs, routing_outputs, FMT(this->annotation_prefix, " routing_network"))); + leave_block("Allocate routing network"); + + /* deal with all checkers */ + enter_block("Allocate execution checkers"); + execution_checkers.reserve(time_bound); + for (size_t i = 0; i < time_bound; ++i) + { + execution_checkers.emplace_back(ram_cpu_checker(pb, + load_instruction_lines[i].address->bits, // prev_pc_addr + load_instruction_lines[i].contents_after->bits, // prev_pc_val + execution_lines[i].cpu_state, // prev_state + execution_lines[i+1].address->bits, // ls_addr, + execution_lines[i+1].contents_before->bits, // ls_prev_val + execution_lines[i+1].contents_after->bits, // ls_next_val + execution_lines[i+1].cpu_state, // next_state + load_instruction_lines[i+1].address->bits, // next_pc_addr + execution_lines[i+1].has_accepted, // next_has_accepted + FMT(annotation_prefix, " execution_checkers_%zu", i))); + } + leave_block("Allocate execution checkers"); + + enter_block("Allocate all memory checkers"); + memory_checkers.reserve(num_memory_lines); + for (size_t i = 0; i < num_memory_lines; ++i) + { + memory_checkers.emplace_back(memory_checker_gadget(pb, + timestamp_size, + *unrouted_memory_lines[i], + routed_memory_lines[i], + FMT(this->annotation_prefix, " memory_checkers_%zu", i))); + } + leave_block("Allocate all memory checkers"); + + /* done */ +} + +template +void ram_universal_gadget::generate_r1cs_constraints() +{ + enter_block("Call to generate_r1cs_constraints of ram_universal_gadget"); + for (size_t i = 0; i < boot_trace_size_bound; ++i) + { + unpack_boot_lines[i].generate_r1cs_constraints(false); + } + + /* ensure that we start with all zeros state */ + for (size_t i = 0; i < this->pb.ap.cpu_state_size(); ++i) + { + generate_r1cs_equals_const_constraint(this->pb, execution_lines[0].cpu_state[i], FieldT::zero()); + } + + /* ensure increasing timestamps */ + for (size_t i = 0; i < num_memory_lines; ++i) + { + generate_r1cs_equals_const_constraint(this->pb, unrouted_memory_lines[i]->timestamp->packed, FieldT(i)); + } + + /* ensure bitness of trace lines on the time side */ + for (size_t i = 0; i < boot_trace_size_bound; ++i) + { + boot_lines[i].generate_r1cs_constraints(true); + } + + execution_lines[0].generate_r1cs_constraints(true); + for (size_t i = 0; i < time_bound; ++i) + { + load_instruction_lines[i].generate_r1cs_constraints(true); + execution_lines[i+1].generate_r1cs_constraints(true); + } + + /* ensure bitness of trace lines on the memory side */ + for (size_t i = 0; i < num_memory_lines; ++i) + { + routed_memory_lines[i].generate_r1cs_constraints(); + } + + /* ensure that load instruction lines really do loads */ + for (size_t i = 0; i < time_bound; ++i) + { + this->pb.add_r1cs_constraint(r1cs_constraint(1, load_instruction_lines[i].contents_before->packed, + load_instruction_lines[i].contents_after->packed), + FMT(this->annotation_prefix, " load_instruction_%zu_is_a_load", i)); + } + + /* ensure correct execution */ + for (size_t i = 0; i < time_bound; ++i) + { + execution_checkers[i].generate_r1cs_constraints(); + } + + /* check memory */ + routing_network->generate_r1cs_constraints(); + + for (size_t i = 0; i < num_memory_lines; ++i) + { + memory_checkers[i].generate_r1cs_constraints(); + } + + /* ensure that PC started at the prescribed value */ + generate_r1cs_equals_const_constraint(this->pb, load_instruction_lines[0].address->packed, FieldT(this->pb.ap.initial_pc_addr())); + + /* ensure that the last state was an accepting one */ + generate_r1cs_equals_const_constraint(this->pb, execution_lines[time_bound].has_accepted, FieldT::one(), "last_state_must_be_accepting"); + + /* print constraint profiling */ + const size_t num_constraints = this->pb.num_constraints(); + const size_t num_variables = this->pb.num_variables(); + + if (!inhibit_profiling_info) + { + print_indent(); printf("* Number of constraints: %zu\n", num_constraints); + print_indent(); printf("* Number of constraints / cycle: %0.1f\n", 1.*num_constraints/this->time_bound); + + print_indent(); printf("* Number of variables: %zu\n", num_variables); + print_indent(); printf("* Number of variables / cycle: %0.1f\n", 1.*num_variables/this->time_bound); + } + leave_block("Call to generate_r1cs_constraints of ram_universal_gadget"); +} + +template +void ram_universal_gadget::generate_r1cs_witness(const ram_boot_trace &boot_trace, + const ram_input_tape &auxiliary_input) +{ + /* assign correct timestamps to all lines */ + for (size_t i = 0; i < num_memory_lines; ++i) + { + this->pb.val(unrouted_memory_lines[i]->timestamp->packed) = FieldT(i); + unrouted_memory_lines[i]->timestamp->generate_r1cs_witness_from_packed(); + } + + /* fill in the initial state */ + const ram_cpu_state initial_state = this->pb.ap.initial_cpu_state(); + execution_lines[0].cpu_state.fill_with_bits(this->pb, initial_state); + + /* fill in the boot section */ + memory_contents memory_after_boot; + + for (auto it : boot_trace.get_all_trace_entries()) + { + const size_t boot_pos = it.first; + assert(boot_pos < boot_trace_size_bound); + const size_t address = it.second.first; + const size_t contents = it.second.second; + + this->pb.val(boot_lines[boot_pos].address->packed) = FieldT(address, true); + this->pb.val(boot_lines[boot_pos].contents_after->packed) = FieldT(contents, true); + boot_lines[boot_pos].generate_r1cs_witness_from_packed(); + + memory_after_boot[address] = contents; + } + + /* do the actual execution */ + ra_memory mem_backend(1ul<<(this->pb.ap.address_size()), this->pb.ap.value_size(), memory_after_boot); + typename ram_input_tape::const_iterator auxiliary_input_it = auxiliary_input.begin(); + + this->pb.val(load_instruction_lines[0].address->packed) = FieldT(this->pb.ap.initial_pc_addr(), true); + load_instruction_lines[0].address->generate_r1cs_witness_from_packed(); + + for (size_t i = 0; i < time_bound; ++i) + { + /* load instruction */ + const size_t pc_addr = this->pb.val(load_instruction_lines[i].address->packed).as_ulong(); + const size_t pc_val = mem_backend.get_value(pc_addr); + + this->pb.val(load_instruction_lines[i].contents_before->packed) = FieldT(pc_val, true); + this->pb.val(load_instruction_lines[i].contents_after->packed) = FieldT(pc_val, true); + load_instruction_lines[i].generate_r1cs_witness_from_packed(); + + /* first fetch the address part of the memory */ + execution_checkers[i].generate_r1cs_witness_address(); + execution_lines[i+1].address->generate_r1cs_witness_from_bits(); + + /* fill it in */ + const size_t load_store_addr = this->pb.val(execution_lines[i+1].address->packed).as_ulong(); + const size_t load_store_prev_val = mem_backend.get_value(load_store_addr); + + this->pb.val(execution_lines[i+1].contents_before->packed) = FieldT(load_store_prev_val, true); + execution_lines[i+1].contents_before->generate_r1cs_witness_from_packed(); + + /* then execute the rest of the instruction */ + execution_checkers[i].generate_r1cs_witness_other(auxiliary_input_it, auxiliary_input.end()); + + /* update the memory possibly changed by the CPU checker */ + execution_lines[i+1].contents_after->generate_r1cs_witness_from_bits(); + const size_t load_store_next_val = this->pb.val(execution_lines[i+1].contents_after->packed).as_ulong(); + mem_backend.set_value(load_store_addr, load_store_next_val); + + /* the next PC address was passed in a bit form, so maintain packed form as well */ + load_instruction_lines[i+1].address->generate_r1cs_witness_from_bits(); + } + + /* + Get the correct memory permutation. + + We sort all memory accesses by address breaking ties by + timestamp. In our routing configuration we pair each memory + access with subsequent access in this ordering. + + That way num_memory_pairs of memory checkers will do a full + cycle over all memory accesses, enforced by the proper ordering + property. + */ + + typedef std::pair mem_pair; /* a pair of address, timestamp */ + std::vector mem_pairs; + + for (size_t i = 0; i < this->num_memory_lines; ++i) + { + mem_pairs.emplace_back(std::make_pair(this->pb.val(unrouted_memory_lines[i]->address->packed).as_ulong(), + this->pb.val(unrouted_memory_lines[i]->timestamp->packed).as_ulong())); + } + + std::sort(mem_pairs.begin(), mem_pairs.end()); + + integer_permutation pi(this->num_memory_lines); + for (size_t i = 0; i < this->num_memory_lines; ++i) + { + const size_t timestamp = this->pb.val(unrouted_memory_lines[i]->timestamp->packed).as_ulong(); + const size_t address = this->pb.val(unrouted_memory_lines[i]->address->packed).as_ulong(); + + const auto it = std::upper_bound(mem_pairs.begin(), mem_pairs.end(), std::make_pair(address, timestamp)); + const size_t prev = (it == mem_pairs.end() ? 0 : it->second); + pi.set(prev, i); + } + + /* route according to the memory permutation */ + routing_network->generate_r1cs_witness(pi); + + for (size_t i = 0; i < this->num_memory_lines; ++i) + { + routed_memory_lines[i].generate_r1cs_witness_from_bits(); + } + + /* generate witness for memory checkers */ + for (size_t i = 0; i < this->num_memory_lines; ++i) + { + memory_checkers[i].generate_r1cs_witness(); + } + + /* repack back the input */ + for (size_t i = 0; i < boot_trace_size_bound; ++i) + { + unpack_boot_lines[i].generate_r1cs_witness_from_bits(); + } + + /* print debugging information */ + if (!inhibit_profiling_info) + { + print_indent(); + printf("* Protoboard satisfied: %s\n", (this->pb.is_satisfied() ? "YES" : "no")); + } +} + +template +void ram_universal_gadget::print_execution_trace() const +{ + for (size_t i = 0; i < boot_trace_size_bound; ++i) + { + printf("Boot process at t=#%zu: store %zu at %zu\n", + i, + this->pb.val(boot_lines[i].contents_after->packed).as_ulong(), + this->pb.val(boot_lines[i].address->packed).as_ulong()); + } + + for (size_t i = 0; i < time_bound; ++i) + { + printf("Execution step %zu:\n", i); + printf(" Loaded instruction %zu from address %zu (ts = %zu)\n", + this->pb.val(load_instruction_lines[i].contents_after->packed).as_ulong(), + this->pb.val(load_instruction_lines[i].address->packed).as_ulong(), + this->pb.val(load_instruction_lines[i].timestamp->packed).as_ulong()); + + printf(" Debugging information from the transition function:\n"); + execution_checkers[i].dump(); + + printf(" Memory operation executed: addr = %zu, contents_before = %zu, contents_after = %zu (ts_before = %zu, ts_after = %zu)\n", + this->pb.val(execution_lines[i+1].address->packed).as_ulong(), + this->pb.val(execution_lines[i+1].contents_before->packed).as_ulong(), + this->pb.val(execution_lines[i+1].contents_after->packed).as_ulong(), + this->pb.val(execution_lines[i].timestamp->packed).as_ulong(), + this->pb.val(execution_lines[i+1].timestamp->packed).as_ulong()); + } +} + +template +void ram_universal_gadget::print_memory_trace() const +{ + for (size_t i = 0; i < num_memory_lines; ++i) + { + printf("Memory access #%zu:\n", i); + printf(" Time side : ts = %zu, address = %zu, contents_before = %zu, contents_after = %zu\n", + this->pb.val(unrouted_memory_lines[i]->timestamp->packed).as_ulong(), + this->pb.val(unrouted_memory_lines[i]->address->packed).as_ulong(), + this->pb.val(unrouted_memory_lines[i]->contents_before->packed).as_ulong(), + this->pb.val(unrouted_memory_lines[i]->contents_after->packed).as_ulong()); + printf(" Memory side: ts = %zu, address = %zu, contents_before = %zu, contents_after = %zu\n", + this->pb.val(routed_memory_lines[i].timestamp->packed).as_ulong(), + this->pb.val(routed_memory_lines[i].address->packed).as_ulong(), + this->pb.val(routed_memory_lines[i].contents_before->packed).as_ulong(), + this->pb.val(routed_memory_lines[i].contents_after->packed).as_ulong()); + } +} + +template +size_t ram_universal_gadget::packed_input_element_size(const ram_architecture_params &ap) +{ + const size_t line_size_bits = ap.address_size() + ap.value_size(); + const size_t max_chunk_size = FieldT::capacity(); + const size_t packed_line_size = div_ceil(line_size_bits, max_chunk_size); + + return packed_line_size; +} + +template +size_t ram_universal_gadget::packed_input_size(const ram_architecture_params &ap, + const size_t boot_trace_size_bound) +{ + return packed_input_element_size(ap) * boot_trace_size_bound; +} + +} // libsnark + +#endif // RAM_UNIVERSAL_GADGET_TCC_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/reductions/ram_to_r1cs/gadgets/trace_lines.hpp b/privacy/zsl/zsl/snark/libsnark/src/reductions/ram_to_r1cs/gadgets/trace_lines.hpp new file mode 100644 index 0000000..f14eceb --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/reductions/ram_to_r1cs/gadgets/trace_lines.hpp @@ -0,0 +1,79 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for trace-line variables. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef TRACE_LINES_HPP_ +#define TRACE_LINES_HPP_ + +#include +#include "relations/ram_computations/rams/ram_params.hpp" + +namespace libsnark { + +/** + * A memory line contains variables for the following: + * - timestamp + * - address + * - contents_before + * - contents_after + * + * Memory lines are used by memory_checker_gadget. + */ +template +class memory_line_variable_gadget : public ram_gadget_base { +public: + + typedef ram_base_field FieldT; + + std::shared_ptr > timestamp; + std::shared_ptr > address; + std::shared_ptr > contents_before; + std::shared_ptr > contents_after; + +public: + + memory_line_variable_gadget(ram_protoboard &pb, + const size_t timestamp_size, + const ram_architecture_params &ap, + const std::string &annotation_prefix=""); + + void generate_r1cs_constraints(const bool enforce_bitness=false); + void generate_r1cs_witness_from_bits(); + void generate_r1cs_witness_from_packed(); + + pb_variable_array all_vars() const; +}; + +/** + * An execution line inherits from a memory line and, in addition, contains + * variables for a CPU state and for a flag denoting if the machine has accepted. + * + * Execution lines are used by execution_checker_gadget. + */ +template +class execution_line_variable_gadget : public memory_line_variable_gadget { +public: + + typedef ram_base_field FieldT; + + pb_variable_array cpu_state; + pb_variable has_accepted; + + execution_line_variable_gadget(ram_protoboard &pb, + const size_t timestamp_size, + const ram_architecture_params &ap, + const std::string &annotation_prefix=""); +}; + +} // libsnark + +#include "reductions/ram_to_r1cs/gadgets/trace_lines.tcc" + +#endif // TRACE_LINES_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/reductions/ram_to_r1cs/gadgets/trace_lines.tcc b/privacy/zsl/zsl/snark/libsnark/src/reductions/ram_to_r1cs/gadgets/trace_lines.tcc new file mode 100644 index 0000000..39171de --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/reductions/ram_to_r1cs/gadgets/trace_lines.tcc @@ -0,0 +1,90 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for trace-line variables. + + See trace_lines.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef TRACE_LINES_TCC_ +#define TRACE_LINES_TCC_ + +namespace libsnark { + +template +memory_line_variable_gadget::memory_line_variable_gadget(ram_protoboard &pb, + const size_t timestamp_size, + const ram_architecture_params &ap, + const std::string &annotation_prefix) : + ram_gadget_base(pb, annotation_prefix) +{ + const size_t address_size = ap.address_size(); + const size_t value_size = ap.value_size(); + + timestamp.reset(new dual_variable_gadget(pb, timestamp_size, FMT(this->annotation_prefix, " timestamp"))); + address.reset(new dual_variable_gadget(pb, address_size, FMT(this->annotation_prefix, " address"))); + contents_before.reset(new dual_variable_gadget(pb, value_size, FMT(this->annotation_prefix, " contents_before"))); + contents_after.reset(new dual_variable_gadget(pb, value_size, FMT(this->annotation_prefix, " contents_after"))); +} + +template +void memory_line_variable_gadget::generate_r1cs_constraints(const bool enforce_bitness) +{ + timestamp->generate_r1cs_constraints(enforce_bitness); + address->generate_r1cs_constraints(enforce_bitness); + contents_before->generate_r1cs_constraints(enforce_bitness); + contents_after->generate_r1cs_constraints(enforce_bitness); +} + +template +void memory_line_variable_gadget::generate_r1cs_witness_from_bits() +{ + timestamp->generate_r1cs_witness_from_bits(); + address->generate_r1cs_witness_from_bits(); + contents_before->generate_r1cs_witness_from_bits(); + contents_after->generate_r1cs_witness_from_bits(); +} + +template +void memory_line_variable_gadget::generate_r1cs_witness_from_packed() +{ + timestamp->generate_r1cs_witness_from_packed(); + address->generate_r1cs_witness_from_packed(); + contents_before->generate_r1cs_witness_from_packed(); + contents_after->generate_r1cs_witness_from_packed(); +} + +template +pb_variable_array > memory_line_variable_gadget::all_vars() const +{ + pb_variable_array r; + r.insert(r.end(), timestamp->bits.begin(), timestamp->bits.end()); + r.insert(r.end(), address->bits.begin(), address->bits.end()); + r.insert(r.end(), contents_before->bits.begin(), contents_before->bits.end()); + r.insert(r.end(), contents_after->bits.begin(), contents_after->bits.end()); + + return r; +} + +template +execution_line_variable_gadget::execution_line_variable_gadget(ram_protoboard &pb, + const size_t timestamp_size, + const ram_architecture_params &ap, + const std::string &annotation_prefix) : + memory_line_variable_gadget(pb, timestamp_size, ap, annotation_prefix) +{ + const size_t cpu_state_size = ap.cpu_state_size(); + + cpu_state.allocate(pb, cpu_state_size, FMT(annotation_prefix, " cpu_state")); + has_accepted.allocate(pb, FMT(annotation_prefix, " has_accepted")); +} + + +} // libsnark + +#endif // TRACE_LINES_TCC_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/reductions/ram_to_r1cs/ram_to_r1cs.hpp b/privacy/zsl/zsl/snark/libsnark/src/reductions/ram_to_r1cs/ram_to_r1cs.hpp new file mode 100644 index 0000000..df24d5d --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/reductions/ram_to_r1cs/ram_to_r1cs.hpp @@ -0,0 +1,59 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for a RAM-to-R1CS reduction, that is, constructing + a R1CS ("Rank-1 Constraint System") from a RAM ("Random-Access Machine"). + + The implementation is a thin layer around a "RAM universal gadget", which is + where most of the work is done. See gadgets/ram_universal_gadget.hpp for details. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef RAM_TO_R1CS_HPP_ +#define RAM_TO_R1CS_HPP_ + +#include "reductions/ram_to_r1cs/gadgets/ram_universal_gadget.hpp" + +namespace libsnark { + +template +class ram_to_r1cs { +public: + + typedef ram_base_field FieldT; + + size_t boot_trace_size_bound; + + ram_protoboard main_protoboard; + pb_variable_array r1cs_input; + std::shared_ptr > universal_gadget; + + ram_to_r1cs(const ram_architecture_params &ap, + const size_t boot_trace_size_bound, + const size_t time_bound); + void instance_map(); + r1cs_constraint_system get_constraint_system() const; + r1cs_auxiliary_input auxiliary_input_map(const ram_boot_trace &boot_trace, + const ram_input_tape &auxiliary_input); + + /* both methods assume that auxiliary_input_map has been called */ + void print_execution_trace() const; + void print_memory_trace() const; + + static std::vector > pack_primary_input_address_and_value(const ram_architecture_params &ap, + const address_and_value &av); + + static r1cs_primary_input > primary_input_map(const ram_architecture_params &ap, + const size_t boot_trace_size_bound, + const ram_boot_trace& boot_trace); +}; + +} // libsnark + +#include "reductions/ram_to_r1cs/ram_to_r1cs.tcc" + +#endif // RAM_TO_R1CS_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/reductions/ram_to_r1cs/ram_to_r1cs.tcc b/privacy/zsl/zsl/snark/libsnark/src/reductions/ram_to_r1cs/ram_to_r1cs.tcc new file mode 100644 index 0000000..1056313 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/reductions/ram_to_r1cs/ram_to_r1cs.tcc @@ -0,0 +1,133 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for a RAM-to-R1CS reduction, that is, constructing + a R1CS ("Rank-1 Constraint System") from a RAM ("Random-Access Machine"). + + See ram_to_r1cs.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef RAM_TO_R1CS_TCC_ +#define RAM_TO_R1CS_TCC_ + +#include + +namespace libsnark { + +template +ram_to_r1cs::ram_to_r1cs(const ram_architecture_params &ap, + const size_t boot_trace_size_bound, + const size_t time_bound) : + boot_trace_size_bound(boot_trace_size_bound), + main_protoboard(ap) +{ + const size_t r1cs_input_size = ram_universal_gadget::packed_input_size(ap, boot_trace_size_bound); + r1cs_input.allocate(main_protoboard, r1cs_input_size, "r1cs_input"); + universal_gadget.reset(new ram_universal_gadget(main_protoboard, + boot_trace_size_bound, + time_bound, + r1cs_input, + "universal_gadget")); + main_protoboard.set_input_sizes(r1cs_input_size); +} + +template +void ram_to_r1cs::instance_map() +{ + enter_block("Call to instance_map of ram_to_r1cs"); + universal_gadget->generate_r1cs_constraints(); + leave_block("Call to instance_map of ram_to_r1cs"); +} + +template +r1cs_constraint_system > ram_to_r1cs::get_constraint_system() const +{ + return main_protoboard.get_constraint_system(); +} + +template +r1cs_primary_input > ram_to_r1cs::auxiliary_input_map(const ram_boot_trace &boot_trace, + const ram_input_tape &auxiliary_input) +{ + enter_block("Call to witness_map of ram_to_r1cs"); + universal_gadget->generate_r1cs_witness(boot_trace, auxiliary_input); +#ifdef DEBUG + const r1cs_primary_input primary_input_from_input_map = ram_to_r1cs::primary_input_map(main_protoboard.ap, boot_trace_size_bound, boot_trace); + const r1cs_primary_input primary_input_from_witness_map = main_protoboard.primary_input(); + assert(primary_input_from_input_map == primary_input_from_witness_map); +#endif + leave_block("Call to witness_map of ram_to_r1cs"); + return main_protoboard.auxiliary_input(); +} + +template +void ram_to_r1cs::print_execution_trace() const +{ + universal_gadget->print_execution_trace(); +} + +template +void ram_to_r1cs::print_memory_trace() const +{ + universal_gadget->print_memory_trace(); +} + +template +std::vector > ram_to_r1cs::pack_primary_input_address_and_value(const ram_architecture_params &ap, + const address_and_value &av) +{ + typedef ram_base_field FieldT; + + const size_t address = av.first; + const size_t contents = av.second; + + const bit_vector address_bits = convert_field_element_to_bit_vector(FieldT(address, true), ap.address_size()); + const bit_vector contents_bits = convert_field_element_to_bit_vector(FieldT(contents, true), ap.value_size()); + + bit_vector trace_element_bits; + trace_element_bits.insert(trace_element_bits.end(), address_bits.begin(), address_bits.end()); + trace_element_bits.insert(trace_element_bits.end(), contents_bits.begin(), contents_bits.end()); + + const std::vector trace_element = pack_bit_vector_into_field_element_vector(trace_element_bits); + + return trace_element; +} + + +template +r1cs_primary_input > ram_to_r1cs::primary_input_map(const ram_architecture_params &ap, + const size_t boot_trace_size_bound, + const ram_boot_trace& boot_trace) +{ + typedef ram_base_field FieldT; + + const size_t packed_input_element_size = ram_universal_gadget::packed_input_element_size(ap); + r1cs_primary_input result(ram_universal_gadget::packed_input_size(ap, boot_trace_size_bound)); + + std::set bound_input_locations; + + for (auto it : boot_trace.get_all_trace_entries()) + { + const size_t input_pos = it.first; + const address_and_value av = it.second; + + assert(input_pos < boot_trace_size_bound); + assert(bound_input_locations.find(input_pos) == bound_input_locations.end()); + + const std::vector packed_input_element = ram_to_r1cs::pack_primary_input_address_and_value(ap, av); + std::copy(packed_input_element.begin(), packed_input_element.end(), result.begin() + packed_input_element_size * (boot_trace_size_bound - 1 - input_pos)); + + bound_input_locations.insert(input_pos); + } + + return result; +} + +} // libsnark + +#endif // RAM_TO_R1CS_TCC_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/reductions/tbcs_to_uscs/get_tbcs_reduction.py b/privacy/zsl/zsl/snark/libsnark/src/reductions/tbcs_to_uscs/get_tbcs_reduction.py new file mode 100644 index 0000000..efefd3c --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/reductions/tbcs_to_uscs/get_tbcs_reduction.py @@ -0,0 +1,32 @@ +#!/usr/bin/env python +## +# @author This file is part of libsnark, developed by SCIPR Lab +# and contributors (see AUTHORS). +# @copyright MIT license (see LICENSE file) + +from __future__ import division +import itertools + +def valid_formula(truth_table, x_coeff, y_coeff, z_coeff, offset): + for x in [0,1]: + for y in [0,1]: + z = truth_table[2*x + y] + # we require that z can be set to the correct value, but can *not* be set to the incorrect one + if ((x*x_coeff + y*y_coeff + z*z_coeff + offset not in [-1, 1]) + or + (x*x_coeff + y*y_coeff + (1-z)*z_coeff + offset in [-1, 1])): + return False + return True + +def all_valid_formulas(truth_table, x_coeff_range, y_coeff_range, z_coeff_range, offset_range): + for x_coeff, y_coeff, z_coeff, offset in itertools.product(x_coeff_range, y_coeff_range, z_coeff_range, offset_range): + if valid_formula(truth_table, x_coeff, y_coeff, z_coeff, offset): + yield x_coeff, y_coeff, z_coeff, offset + +if __name__ == '__main__': + x_coeff_range, y_coeff_range, z_coeff_range, offset_range = range(-2, 3), range(-2, 3), range(1, 5), range(-5, 6) + print "Possible coefficients for x: %s, for y: %s, for z: %s, for offset: %s" % (x_coeff_range, y_coeff_range, z_coeff_range, offset_range) + for truth_table in itertools.product([0, 1], repeat=4): + print "Truth table (00, 01, 10, 11):", truth_table + for x_coeff, y_coeff, z_coeff, offset in all_valid_formulas(truth_table, x_coeff_range, y_coeff_range, z_coeff_range, offset_range): + print " %s * x + %s * y + %s * z + %s \in {-1, 1}" % (x_coeff, y_coeff, z_coeff, offset) diff --git a/privacy/zsl/zsl/snark/libsnark/src/reductions/tbcs_to_uscs/tbcs_reduction.txt b/privacy/zsl/zsl/snark/libsnark/src/reductions/tbcs_to_uscs/tbcs_reduction.txt new file mode 100644 index 0000000..d7ceb0d --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/reductions/tbcs_to_uscs/tbcs_reduction.txt @@ -0,0 +1,33 @@ +Possible coefficients for x: [-2, -1, 0, 1, 2], for y: [-2, -1, 0, 1, 2], for z: [1, 2, 3, 4], for offset: [-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5] +Truth table (00, 01, 10, 11): (0, 0, 0, 0) + 0 * x + 0 * y + 1 * z + 1 \in {-1, 1} +Truth table (00, 01, 10, 11): (0, 0, 0, 1) + -2 * x + -2 * y + 4 * z + 1 \in {-1, 1} +Truth table (00, 01, 10, 11): (0, 0, 1, 0) + -2 * x + 2 * y + 4 * z + -1 \in {-1, 1} +Truth table (00, 01, 10, 11): (0, 0, 1, 1) + -1 * x + 0 * y + 1 * z + 1 \in {-1, 1} +Truth table (00, 01, 10, 11): (0, 1, 0, 0) + 2 * x + -2 * y + 4 * z + -1 \in {-1, 1} +Truth table (00, 01, 10, 11): (0, 1, 0, 1) + 0 * x + 1 * y + 1 * z + -1 \in {-1, 1} +Truth table (00, 01, 10, 11): (0, 1, 1, 0) + 1 * x + 1 * y + 1 * z + -1 \in {-1, 1} +Truth table (00, 01, 10, 11): (0, 1, 1, 1) + -2 * x + -2 * y + 4 * z + -1 \in {-1, 1} +Truth table (00, 01, 10, 11): (1, 0, 0, 0) + 2 * x + 2 * y + 4 * z + -3 \in {-1, 1} +Truth table (00, 01, 10, 11): (1, 0, 0, 1) + 1 * x + 1 * y + 1 * z + -2 \in {-1, 1} +Truth table (00, 01, 10, 11): (1, 0, 1, 0) + 0 * x + -1 * y + 1 * z + 0 \in {-1, 1} +Truth table (00, 01, 10, 11): (1, 0, 1, 1) + -2 * x + 2 * y + 4 * z + -3 \in {-1, 1} +Truth table (00, 01, 10, 11): (1, 1, 0, 0) + -1 * x + 0 * y + 1 * z + 0 \in {-1, 1} +Truth table (00, 01, 10, 11): (1, 1, 0, 1) + 2 * x + -2 * y + 4 * z + -3 \in {-1, 1} +Truth table (00, 01, 10, 11): (1, 1, 1, 0) + 2 * x + 2 * y + 4 * z + -5 \in {-1, 1} +Truth table (00, 01, 10, 11): (1, 1, 1, 1) + 0 * x + 0 * y + 1 * z + 0 \in {-1, 1} diff --git a/privacy/zsl/zsl/snark/libsnark/src/reductions/tbcs_to_uscs/tbcs_to_uscs.hpp b/privacy/zsl/zsl/snark/libsnark/src/reductions/tbcs_to_uscs/tbcs_to_uscs.hpp new file mode 100644 index 0000000..92fe642 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/reductions/tbcs_to_uscs/tbcs_to_uscs.hpp @@ -0,0 +1,55 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for a TBCS-to-USCS reduction, that is, constructing + a USCS ("Unitary-Square Constraint System") from a TBCS ("Two-input Boolean Circuit Satisfiability"). + + The reduction is straightforward: each non-output wire is mapped to a + corresponding USCS constraint that enforces the wire to carry a boolean value; + each 2-input boolean gate is mapped to a corresponding USCS constraint that + enforces correct computation of the gate; each output wire is mapped to a + corresponding USCS constraint that enforces that the output is zero. + + The mapping of a gate to a USCS constraint is due to \[GOS12]. + + References: + + \[GOS12]: + "New techniques for noninteractive zero-knowledge", + Jens Groth, Rafail Ostrovsky, Amit Sahai + JACM 2012, + + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef TBCS_TO_USCS_HPP_ +#define TBCS_TO_USCS_HPP_ + +#include "relations/constraint_satisfaction_problems/uscs/uscs.hpp" +#include "relations/circuit_satisfaction_problems/tbcs/tbcs.hpp" + +namespace libsnark { + +/** + * Instance map for the TBCS-to-USCS reduction. + */ +template +uscs_constraint_system tbcs_to_uscs_instance_map(const tbcs_circuit &circuit); + +/** + * Witness map for the TBCS-to-USCS reduction. + */ +template +uscs_variable_assignment tbcs_to_uscs_witness_map(const tbcs_circuit &circuit, + const tbcs_primary_input &primary_input, + const tbcs_auxiliary_input &auxiliary_input); + +} // libsnark + +#include "reductions/tbcs_to_uscs/tbcs_to_uscs.tcc" + +#endif // TBCS_TO_USCS_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/reductions/tbcs_to_uscs/tbcs_to_uscs.tcc b/privacy/zsl/zsl/snark/libsnark/src/reductions/tbcs_to_uscs/tbcs_to_uscs.tcc new file mode 100644 index 0000000..a81d381 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/reductions/tbcs_to_uscs/tbcs_to_uscs.tcc @@ -0,0 +1,165 @@ +/** @file +***************************************************************************** + +Implementation of interfaces for a TBCS-to-USCS reduction. + +See tbcs_to_uscs.hpp . + +***************************************************************************** +* @author This file is part of libsnark, developed by SCIPR Lab +* and contributors (see AUTHORS). +* @copyright MIT license (see LICENSE file) +*****************************************************************************/ + +#ifndef TBCS_TO_USCS_TCC_ +#define TBCS_TO_USCS_TCC_ + +#include "algebra/fields/field_utils.hpp" + +namespace libsnark { + +template +uscs_constraint_system tbcs_to_uscs_instance_map(const tbcs_circuit &circuit) +{ + assert(circuit.is_valid()); + uscs_constraint_system result; + +#ifdef DEBUG + result.variable_annotations = circuit.variable_annotations; +#endif + + result.primary_input_size = circuit.primary_input_size; + result.auxiliary_input_size = circuit.auxiliary_input_size + circuit.gates.size(); + + for (auto &g : circuit.gates) + { + const variable x(g.left_wire); + const variable y(g.right_wire); + const variable z(g.output); + +#ifdef DEBUG + auto it = circuit.gate_annotations.find(g.output); + const std::string annotation = (it != circuit.gate_annotations.end() ? it->second : FORMAT("", "compute_wire_%zu", g.output)); +#else + const std::string annotation = ""; +#endif + + switch (g.type) + { + case TBCS_GATE_CONSTANT_0: + /* Truth table (00, 01, 10, 11): (0, 0, 0, 0) + 0 * x + 0 * y + 1 * z + 1 \in {-1, 1} */ + result.add_constraint(0 * x + 0 * y + 1 * z + 1, annotation); + break; + case TBCS_GATE_AND: + /* Truth table (00, 01, 10, 11): (0, 0, 0, 1) + -2 * x + -2 * y + 4 * z + 1 \in {-1, 1} */ + result.add_constraint(-2 * x + -2 * y + 4 * z + 1, annotation); + break; + case TBCS_GATE_X_AND_NOT_Y: + /* Truth table (00, 01, 10, 11): (0, 0, 1, 0) + -2 * x + 2 * y + 4 * z + -1 \in {-1, 1} */ + result.add_constraint(-2 * x + 2 * y + 4 * z + -1, annotation); + break; + case TBCS_GATE_X: + /* Truth table (00, 01, 10, 11): (0, 0, 1, 1) + -1 * x + 0 * y + 1 * z + 1 \in {-1, 1} */ + result.add_constraint(-1 * x + 0 * y + 1 * z + 1, annotation); + break; + case TBCS_GATE_NOT_X_AND_Y: + /* Truth table (00, 01, 10, 11): (0, 1, 0, 0) + 2 * x + -2 * y + 4 * z + -1 \in {-1, 1} */ + result.add_constraint(2 * x + -2 * y + 4 * z + -1, annotation); + break; + case TBCS_GATE_Y: + /* Truth table (00, 01, 10, 11): (0, 1, 0, 1) + 0 * x + 1 * y + 1 * z + -1 \in {-1, 1} */ + result.add_constraint(0 * x + 1 * y + 1 * z + -1, annotation); + break; + case TBCS_GATE_XOR: + /* Truth table (00, 01, 10, 11): (0, 1, 1, 0) + 1 * x + 1 * y + 1 * z + -1 \in {-1, 1} */ + result.add_constraint(1 * x + 1 * y + 1 * z + -1, annotation); + break; + case TBCS_GATE_OR: + /* Truth table (00, 01, 10, 11): (0, 1, 1, 1) + -2 * x + -2 * y + 4 * z + -1 \in {-1, 1} */ + result.add_constraint(-2 * x + -2 * y + 4 * z + -1, annotation); + break; + case TBCS_GATE_NOR: + /* Truth table (00, 01, 10, 11): (1, 0, 0, 0) + 2 * x + 2 * y + 4 * z + -3 \in {-1, 1} */ + result.add_constraint(2 * x + 2 * y + 4 * z + -3, annotation); + break; + case TBCS_GATE_EQUIVALENCE: + /* Truth table (00, 01, 10, 11): (1, 0, 0, 1) + 1 * x + 1 * y + 1 * z + -2 \in {-1, 1} */ + result.add_constraint(1 * x + 1 * y + 1 * z + -2, annotation); + break; + case TBCS_GATE_NOT_Y: + /* Truth table (00, 01, 10, 11): (1, 0, 1, 0) + 0 * x + -1 * y + 1 * z + 0 \in {-1, 1} */ + result.add_constraint(0 * x + -1 * y + 1 * z + 0, annotation); + break; + case TBCS_GATE_IF_Y_THEN_X: + /* Truth table (00, 01, 10, 11): (1, 0, 1, 1) + -2 * x + 2 * y + 4 * z + -3 \in {-1, 1} */ + result.add_constraint(-2 * x + 2 * y + 4 * z + -3, annotation); + break; + case TBCS_GATE_NOT_X: + /* Truth table (00, 01, 10, 11): (1, 1, 0, 0) + -1 * x + 0 * y + 1 * z + 0 \in {-1, 1} */ + result.add_constraint(-1 * x + 0 * y + 1 * z + 0, annotation); + break; + case TBCS_GATE_IF_X_THEN_Y: + /* Truth table (00, 01, 10, 11): (1, 1, 0, 1) + 2 * x + -2 * y + 4 * z + -3 \in {-1, 1} */ + result.add_constraint(2 * x + -2 * y + 4 * z + -3, annotation); + break; + case TBCS_GATE_NAND: + /* Truth table (00, 01, 10, 11): (1, 1, 1, 0) + 2 * x + 2 * y + 4 * z + -5 \in {-1, 1} */ + result.add_constraint(2 * x + 2 * y + 4 * z + -5, annotation); + break; + case TBCS_GATE_CONSTANT_1: + /* Truth table (00, 01, 10, 11): (1, 1, 1, 1) + 0 * x + 0 * y + 1 * z + 0 \in {-1, 1} */ + result.add_constraint(0 * x + 0 * y + 1 * z + 0, annotation); + break; + default: + assert(0); + } + } + + for (size_t i = 0; i < circuit.primary_input_size + circuit.auxiliary_input_size + circuit.gates.size(); ++i) + { + /* require that 2 * wire - 1 \in {-1,1}, that is wire \in {0,1} */ + result.add_constraint(2 * variable(i) - 1, FMT("", "wire_%zu", i)); + } + + for (auto &g : circuit.gates) + { + if (g.is_circuit_output) + { + /* require that output + 1 \in {-1,1}, this together with output binary (above) enforces output = 0 */ + result.add_constraint(variable(g.output) + 1, FMT("", "output_%zu", g.output)); + } + } + + return result; +} + +template +uscs_variable_assignment tbcs_to_uscs_witness_map(const tbcs_circuit &circuit, + const tbcs_primary_input &primary_input, + const tbcs_auxiliary_input &auxiliary_input) +{ + const tbcs_variable_assignment all_wires = circuit.get_all_wires(primary_input, auxiliary_input); + const uscs_variable_assignment result = convert_bit_vector_to_field_element_vector(all_wires); + return result; +} + +} // libsnark + + +#endif // TBCS_TO_USCS_TCC_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/reductions/uscs_to_ssp/uscs_to_ssp.hpp b/privacy/zsl/zsl/snark/libsnark/src/reductions/uscs_to_ssp/uscs_to_ssp.hpp new file mode 100644 index 0000000..d6352db --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/reductions/uscs_to_ssp/uscs_to_ssp.hpp @@ -0,0 +1,68 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for a USCS-to-SSP reduction, that is, constructing + a SSP ("Square Span Program") from a USCS ("boolean circuit with 2-input gates"). + + SSPs are defined in \[DFGK14], and construced for USCS also in \[DFGK14]. + + The implementation of the reduction adapts to \[DFGK14], extends, and optimizes + the efficient QAP-based approach described in Appendix E of \[BCGTV13]. + + References: + + \[BCGTV13] + "SNARKs for C: Verifying Program Executions Succinctly and in Zero Knowledge", + Eli Ben-Sasson, Alessandro Chiesa, Daniel Genkin, Eran Tromer, Madars Virza, + CRYPTO 2013, + + + \[DFGK14]: + "Square Span Programs with Applications to Succinct NIZK Arguments" + George Danezis, Cedric Fournet, Jens Groth, Markulf Kohlweiss, + ASIACRYPT 2014, + + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef USCS_TO_SSP_HPP_ +#define USCS_TO_SSP_HPP_ + +#include "relations/arithmetic_programs/ssp/ssp.hpp" +#include "relations/constraint_satisfaction_problems/uscs/uscs.hpp" + +namespace libsnark { + +/** + * Instance map for the USCS-to-SSP reduction. + */ +template +ssp_instance uscs_to_ssp_instance_map(const uscs_constraint_system &cs); + +/** + * Instance map for the USCS-to-SSP reduction followed by evaluation of the resulting SSP instance. + */ +template +ssp_instance_evaluation uscs_to_ssp_instance_map_with_evaluation(const uscs_constraint_system &cs, + const FieldT &t); + +/** + * Witness map for the USCS-to-SSP reduction. + * + * The witness map takes zero knowledge into account when d is random. + */ +template +ssp_witness uscs_to_ssp_witness_map(const uscs_constraint_system &cs, + const uscs_primary_input &primary_input, + const uscs_auxiliary_input &auxiliary_input, + const FieldT &d); + +} // libsnark + +#include "reductions/uscs_to_ssp/uscs_to_ssp.tcc" + +#endif // USCS_TO_SSP_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/reductions/uscs_to_ssp/uscs_to_ssp.tcc b/privacy/zsl/zsl/snark/libsnark/src/reductions/uscs_to_ssp/uscs_to_ssp.tcc new file mode 100644 index 0000000..95dd12a --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/reductions/uscs_to_ssp/uscs_to_ssp.tcc @@ -0,0 +1,242 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for a USCS-to-SSP reduction. + + See uscs_to_ssp.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef USCS_TO_SSP_TCC_ +#define USCS_TO_SSP_TCC_ + +#include "common/profiling.hpp" +#include "common/utils.hpp" +#include "algebra/evaluation_domain/evaluation_domain.hpp" + +namespace libsnark { + +/** + * Instance map for the USCS-to-SSP reduction. + * + * Namely, given a USCS constraint system cs, construct a SSP instance for which: + * V := (V_0(z),V_1(z),...,V_m(z)) + * where + * m = number of variables of the SSP + * and + * each V_i is expressed in the Lagrange basis. + */ +template +ssp_instance uscs_to_ssp_instance_map(const uscs_constraint_system &cs) +{ + enter_block("Call to uscs_to_ssp_instance_map"); + + const std::shared_ptr > domain = get_evaluation_domain(cs.num_constraints()); + + enter_block("Compute polynomials V in Lagrange basis"); + std::vector > V_in_Lagrange_basis(cs.num_variables()+1); + for (size_t i = 0; i < cs.num_constraints(); ++i) + { + for (size_t j = 0; j < cs.constraints[i].terms.size(); ++j) + { + V_in_Lagrange_basis[cs.constraints[i].terms[j].index][i] += cs.constraints[i].terms[j].coeff; + } + } + for (size_t i = cs.num_constraints(); i < domain->m; ++i) + { + V_in_Lagrange_basis[0][i] += FieldT::one(); + } + leave_block("Compute polynomials V in Lagrange basis"); + + leave_block("Call to uscs_to_ssp_instance_map"); + + return ssp_instance(domain, + cs.num_variables(), + domain->m, + cs.num_inputs(), + std::move(V_in_Lagrange_basis)); +} + +/** + * Instance map for the USCS-to-SSP reduction followed by evaluation of the resulting SSP instance. + * + * Namely, given a USCS constraint system cs and a field element t, construct + * a SSP instance (evaluated at t) for which: + * Vt := (V_0(t),V_1(t),...,V_m(t)) + * Ht := (1,t,t^2,...,t^n) + * Zt := Z(t) = "vanishing polynomial of a certain set S, evaluated at t" + * where + * m = number of variables of the SSP + * n = degree of the SSP + */ +template +ssp_instance_evaluation uscs_to_ssp_instance_map_with_evaluation(const uscs_constraint_system &cs, + const FieldT &t) +{ + enter_block("Call to uscs_to_ssp_instance_map_with_evaluation"); + + const std::shared_ptr > domain = get_evaluation_domain(cs.num_constraints()); + + std::vector Vt(cs.num_variables()+1, FieldT::zero()); + std::vector Ht(domain->m+1); + + const FieldT Zt = domain->compute_Z(t); + + enter_block("Compute evaluations of V and H at t"); + const std::vector u = domain->lagrange_coeffs(t); + for (size_t i = 0; i < cs.num_constraints(); ++i) + { + for (size_t j = 0; j < cs.constraints[i].terms.size(); ++j) + { + Vt[cs.constraints[i].terms[j].index] += u[i]*cs.constraints[i].terms[j].coeff; + } + } + for (size_t i = cs.num_constraints(); i < domain->m; ++i) + { + Vt[0] += u[i]; /* dummy constraint: 1^2 = 1 */ + } + FieldT ti = FieldT::one(); + for (size_t i = 0; i < domain->m+1; ++i) + { + Ht[i] = ti; + ti *= t; + } + leave_block("Compute evaluations of V and H at t"); + + leave_block("Call to uscs_to_ssp_instance_map_with_evaluation"); + + return ssp_instance_evaluation(domain, + cs.num_variables(), + domain->m, + cs.num_inputs(), + t, + std::move(Vt), + std::move(Ht), + Zt); +} + +/** + * Witness map for the USCS-to-SSP reduction. + * + * The witness map takes zero knowledge into account when d is random. + * + * More precisely, compute the coefficients + * h_0,h_1,...,h_n + * of the polynomial + * H(z) := (V(z)^2-1)/Z(z) + * where + * V(z) := V_0(z) + \sum_{k=1}^{m} w_k V_k(z) + d * Z(z) + * Z(z) := "vanishing polynomial of set S" + * and + * m = number of variables of the SSP + * n = degree of the SSP + * + * This is done as follows: + * (1) compute evaluations of V on S = {sigma_1,...,sigma_n} + * (2) compute coefficients of V + * (3) compute evaluations of V on T = "coset of S" + * (4) compute evaluation of H on T + * (5) compute coefficients of H + * (6) patch H to account for d (i.e., add coefficients of the polynomial 2*d*V(z) + d*d*Z(z) ) + * + * The code below is not as simple as the above high-level description due to + * some reshuffling to save space. + */ +template +ssp_witness uscs_to_ssp_witness_map(const uscs_constraint_system &cs, + const uscs_primary_input &primary_input, + const uscs_auxiliary_input &auxiliary_input, + const FieldT &d) +{ + enter_block("Call to uscs_to_ssp_witness_map"); + + /* sanity check */ + + assert(cs.is_satisfied(primary_input, auxiliary_input)); + + uscs_variable_assignment full_variable_assignment = primary_input; + full_variable_assignment.insert(full_variable_assignment.end(), auxiliary_input.begin(), auxiliary_input.end()); + + const std::shared_ptr > domain = get_evaluation_domain(cs.num_constraints()); + + enter_block("Compute evaluation of polynomial V on set S"); + std::vector aA(domain->m, FieldT::zero()); + assert(domain->m >= cs.num_constraints()); + for (size_t i = 0; i < cs.num_constraints(); ++i) + { + aA[i] += cs.constraints[i].evaluate(full_variable_assignment); + } + for (size_t i = cs.num_constraints(); i < domain->m; ++i) + { + aA[i] += FieldT::one(); + } + leave_block("Compute evaluation of polynomial V on set S"); + + enter_block("Compute coefficients of polynomial V"); + domain->iFFT(aA); + leave_block("Compute coefficients of polynomial V"); + + enter_block("Compute ZK-patch"); + std::vector coefficients_for_H(domain->m+1, FieldT::zero()); +#ifdef MULTICORE +#pragma omp parallel for +#endif + /* add coefficients of the polynomial 2*d*V(z) + d*d*Z(z) */ + for (size_t i = 0; i < domain->m; ++i) + { + coefficients_for_H[i] = FieldT(2)*d*aA[i]; + } + domain->add_poly_Z(d.squared(), coefficients_for_H); + leave_block("Compute ZK-patch"); + + enter_block("Compute evaluation of polynomial V on set T"); + domain->cosetFFT(aA, FieldT::multiplicative_generator); + leave_block("Compute evaluation of polynomial V on set T"); + + enter_block("Compute evaluation of polynomial H on set T"); + std::vector &H_tmp = aA; // can overwrite aA because it is not used later +#ifdef MULTICORE +#pragma omp parallel for +#endif + for (size_t i = 0; i < domain->m; ++i) + { + H_tmp[i] = aA[i].squared()-FieldT::one(); + } + + enter_block("Divide by Z on set T"); + domain->divide_by_Z_on_coset(H_tmp); + leave_block("Divide by Z on set T"); + + leave_block("Compute evaluation of polynomial H on set T"); + + enter_block("Compute coefficients of polynomial H"); + domain->icosetFFT(H_tmp, FieldT::multiplicative_generator); + leave_block("Compute coefficients of polynomial H"); + + enter_block("Compute sum of H and ZK-patch"); +#ifdef MULTICORE +#pragma omp parallel for +#endif + for (size_t i = 0; i < domain->m; ++i) + { + coefficients_for_H[i] += H_tmp[i]; + } + leave_block("Compute sum of H and ZK-patch"); + + leave_block("Call to uscs_to_ssp_witness_map"); + + return ssp_witness(cs.num_variables(), + domain->m, + cs.num_inputs(), + d, + full_variable_assignment, + std::move(coefficients_for_H)); +} + +} // libsnark + +#endif // USCS_TO_SSP_TCC_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/relations/arithmetic_programs/qap/qap.hpp b/privacy/zsl/zsl/snark/libsnark/src/relations/arithmetic_programs/qap/qap.hpp new file mode 100644 index 0000000..4991d20 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/relations/arithmetic_programs/qap/qap.hpp @@ -0,0 +1,193 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for a QAP ("Quadratic Arithmetic Program"). + + QAPs are defined in \[GGPR13]. + + References: + + \[GGPR13]: + "Quadratic span programs and succinct NIZKs without PCPs", + Rosario Gennaro, Craig Gentry, Bryan Parno, Mariana Raykova, + EUROCRYPT 2013, + + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef QAP_HPP_ +#define QAP_HPP_ + +#include "algebra/evaluation_domain/evaluation_domain.hpp" + +namespace libsnark { + +/* forward declaration */ +template +class qap_witness; + +/** + * A QAP instance. + * + * Specifically, the datastructure stores: + * - a choice of domain (corresponding to a certain subset of the field); + * - the number of variables, the degree, and the number of inputs; and + * - coefficients of the A,B,C polynomials in the Lagrange basis. + * + * There is no need to store the Z polynomial because it is uniquely + * determined by the domain (as Z is its vanishing polynomial). + */ +template +class qap_instance { +private: + size_t num_variables_; + size_t degree_; + size_t num_inputs_; + +public: + std::shared_ptr > domain; + + std::vector > A_in_Lagrange_basis; + std::vector > B_in_Lagrange_basis; + std::vector > C_in_Lagrange_basis; + + qap_instance(const std::shared_ptr > &domain, + const size_t num_variables, + const size_t degree, + const size_t num_inputs, + const std::vector > &A_in_Lagrange_basis, + const std::vector > &B_in_Lagrange_basis, + const std::vector > &C_in_Lagrange_basis); + + qap_instance(const std::shared_ptr > &domain, + const size_t num_variables, + const size_t degree, + const size_t num_inputs, + std::vector > &&A_in_Lagrange_basis, + std::vector > &&B_in_Lagrange_basis, + std::vector > &&C_in_Lagrange_basis); + + qap_instance(const qap_instance &other) = default; + qap_instance(qap_instance &&other) = default; + qap_instance& operator=(const qap_instance &other) = default; + qap_instance& operator=(qap_instance &&other) = default; + + size_t num_variables() const; + size_t degree() const; + size_t num_inputs() const; + + bool is_satisfied(const qap_witness &witness) const; +}; + +/** + * A QAP instance evaluation is a QAP instance that is evaluated at a field element t. + * + * Specifically, the datastructure stores: + * - a choice of domain (corresponding to a certain subset of the field); + * - the number of variables, the degree, and the number of inputs; + * - a field element t; + * - evaluations of the A,B,C (and Z) polynomials at t; + * - evaluations of all monomials of t; + * - counts about how many of the above evaluations are in fact non-zero. + */ +template +class qap_instance_evaluation { +private: + size_t num_variables_; + size_t degree_; + size_t num_inputs_; +public: + std::shared_ptr > domain; + + FieldT t; + + std::vector At, Bt, Ct, Ht; + + FieldT Zt; + + qap_instance_evaluation(const std::shared_ptr > &domain, + const size_t num_variables, + const size_t degree, + const size_t num_inputs, + const FieldT &t, + const std::vector &At, + const std::vector &Bt, + const std::vector &Ct, + const std::vector &Ht, + const FieldT &Zt); + qap_instance_evaluation(const std::shared_ptr > &domain, + const size_t num_variables, + const size_t degree, + const size_t num_inputs, + const FieldT &t, + std::vector &&At, + std::vector &&Bt, + std::vector &&Ct, + std::vector &&Ht, + const FieldT &Zt); + + qap_instance_evaluation(const qap_instance_evaluation &other) = default; + qap_instance_evaluation(qap_instance_evaluation &&other) = default; + qap_instance_evaluation& operator=(const qap_instance_evaluation &other) = default; + qap_instance_evaluation& operator=(qap_instance_evaluation &&other) = default; + + size_t num_variables() const; + size_t degree() const; + size_t num_inputs() const; + + bool is_satisfied(const qap_witness &witness) const; +}; + +/** + * A QAP witness. + */ +template +class qap_witness { +private: + size_t num_variables_; + size_t degree_; + size_t num_inputs_; + +public: + FieldT d1, d2, d3; + + std::vector coefficients_for_ABCs; + std::vector coefficients_for_H; + + qap_witness(const size_t num_variables, + const size_t degree, + const size_t num_inputs, + const FieldT &d1, + const FieldT &d2, + const FieldT &d3, + const std::vector &coefficients_for_ABCs, + const std::vector &coefficients_for_H); + + qap_witness(const size_t num_variables, + const size_t degree, + const size_t num_inputs, + const FieldT &d1, + const FieldT &d2, + const FieldT &d3, + const std::vector &coefficients_for_ABCs, + std::vector &&coefficients_for_H); + + qap_witness(const qap_witness &other) = default; + qap_witness(qap_witness &&other) = default; + qap_witness& operator=(const qap_witness &other) = default; + qap_witness& operator=(qap_witness &&other) = default; + + size_t num_variables() const; + size_t degree() const; + size_t num_inputs() const; +}; + +} // libsnark + +#include "relations/arithmetic_programs/qap/qap.tcc" + +#endif // QAP_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/relations/arithmetic_programs/qap/qap.tcc b/privacy/zsl/zsl/snark/libsnark/src/relations/arithmetic_programs/qap/qap.tcc new file mode 100644 index 0000000..a4a3c96 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/relations/arithmetic_programs/qap/qap.tcc @@ -0,0 +1,324 @@ +/** @file +***************************************************************************** + +Implementation of interfaces for a QAP ("Quadratic Arithmetic Program"). + +See qap.hpp . + +***************************************************************************** +* @author This file is part of libsnark, developed by SCIPR Lab +* and contributors (see AUTHORS). +* @copyright MIT license (see LICENSE file) +*****************************************************************************/ + +#ifndef QAP_TCC_ +#define QAP_TCC_ + +#include "common/profiling.hpp" +#include "common/utils.hpp" +#include "algebra/evaluation_domain/evaluation_domain.hpp" +#include "algebra/scalar_multiplication/multiexp.hpp" + +namespace libsnark { + +template +qap_instance::qap_instance(const std::shared_ptr > &domain, + const size_t num_variables, + const size_t degree, + const size_t num_inputs, + const std::vector > &A_in_Lagrange_basis, + const std::vector > &B_in_Lagrange_basis, + const std::vector > &C_in_Lagrange_basis) : + num_variables_(num_variables), + degree_(degree), + num_inputs_(num_inputs), + domain(domain), + A_in_Lagrange_basis(A_in_Lagrange_basis), + B_in_Lagrange_basis(B_in_Lagrange_basis), + C_in_Lagrange_basis(C_in_Lagrange_basis) +{ +} + +template +qap_instance::qap_instance(const std::shared_ptr > &domain, + const size_t num_variables, + const size_t degree, + const size_t num_inputs, + std::vector > &&A_in_Lagrange_basis, + std::vector > &&B_in_Lagrange_basis, + std::vector > &&C_in_Lagrange_basis) : + num_variables_(num_variables), + degree_(degree), + num_inputs_(num_inputs), + domain(domain), + A_in_Lagrange_basis(std::move(A_in_Lagrange_basis)), + B_in_Lagrange_basis(std::move(B_in_Lagrange_basis)), + C_in_Lagrange_basis(std::move(C_in_Lagrange_basis)) +{ +} + +template +size_t qap_instance::num_variables() const +{ + return num_variables_; +} + +template +size_t qap_instance::degree() const +{ + return degree_; +} + +template +size_t qap_instance::num_inputs() const +{ + return num_inputs_; +} + +template +bool qap_instance::is_satisfied(const qap_witness &witness) const +{ + const FieldT t = FieldT::random_element(); + + std::vector At(this->num_variables()+1, FieldT::zero()); + std::vector Bt(this->num_variables()+1, FieldT::zero()); + std::vector Ct(this->num_variables()+1, FieldT::zero()); + std::vector Ht(this->degree()+1); + + const FieldT Zt = this->domain->compute_Z(t); + + const std::vector u = this->domain->lagrange_coeffs(t); + + for (size_t i = 0; i < this->num_variables()+1; ++i) + { + for (auto &el : A_in_Lagrange_basis[i]) + { + At[i] += u[el.first] * el.second; + } + + for (auto &el : B_in_Lagrange_basis[i]) + { + Bt[i] += u[el.first] * el.second; + } + + for (auto &el : C_in_Lagrange_basis[i]) + { + Ct[i] += u[el.first] * el.second; + } + } + + FieldT ti = FieldT::one(); + for (size_t i = 0; i < this->degree()+1; ++i) + { + Ht[i] = ti; + ti *= t; + } + + const qap_instance_evaluation eval_qap_inst(this->domain, + this->num_variables(), + this->degree(), + this->num_inputs(), + t, + std::move(At), + std::move(Bt), + std::move(Ct), + std::move(Ht), + Zt); + return eval_qap_inst.is_satisfied(witness); +} + +template +qap_instance_evaluation::qap_instance_evaluation(const std::shared_ptr > &domain, + const size_t num_variables, + const size_t degree, + const size_t num_inputs, + const FieldT &t, + const std::vector &At, + const std::vector &Bt, + const std::vector &Ct, + const std::vector &Ht, + const FieldT &Zt) : + num_variables_(num_variables), + degree_(degree), + num_inputs_(num_inputs), + domain(domain), + t(t), + At(At), + Bt(Bt), + Ct(Ct), + Ht(Ht), + Zt(Zt) +{ +} + +template +qap_instance_evaluation::qap_instance_evaluation(const std::shared_ptr > &domain, + const size_t num_variables, + const size_t degree, + const size_t num_inputs, + const FieldT &t, + std::vector &&At, + std::vector &&Bt, + std::vector &&Ct, + std::vector &&Ht, + const FieldT &Zt) : + num_variables_(num_variables), + degree_(degree), + num_inputs_(num_inputs), + domain(domain), + t(t), + At(std::move(At)), + Bt(std::move(Bt)), + Ct(std::move(Ct)), + Ht(std::move(Ht)), + Zt(Zt) +{ +} + +template +size_t qap_instance_evaluation::num_variables() const +{ + return num_variables_; +} + +template +size_t qap_instance_evaluation::degree() const +{ + return degree_; +} + +template +size_t qap_instance_evaluation::num_inputs() const +{ + return num_inputs_; +} + +template +bool qap_instance_evaluation::is_satisfied(const qap_witness &witness) const +{ + + if (this->num_variables() != witness.num_variables()) + { + return false; + } + + if (this->degree() != witness.degree()) + { + return false; + } + + if (this->num_inputs() != witness.num_inputs()) + { + return false; + } + + if (this->num_variables() != witness.coefficients_for_ABCs.size()) + { + return false; + } + + if (this->degree()+1 != witness.coefficients_for_H.size()) + { + return false; + } + + if (this->At.size() != this->num_variables()+1 || this->Bt.size() != this->num_variables()+1 || this->Ct.size() != this->num_variables()+1) + { + return false; + } + + if (this->Ht.size() != this->degree()+1) + { + return false; + } + + if (this->Zt != this->domain->compute_Z(this->t)) + { + return false; + } + + FieldT ans_A = this->At[0] + witness.d1*this->Zt; + FieldT ans_B = this->Bt[0] + witness.d2*this->Zt; + FieldT ans_C = this->Ct[0] + witness.d3*this->Zt; + FieldT ans_H = FieldT::zero(); + + ans_A = ans_A + naive_plain_exp(this->At.begin()+1, this->At.begin()+1+this->num_variables(), + witness.coefficients_for_ABCs.begin(), witness.coefficients_for_ABCs.begin()+this->num_variables()); + ans_B = ans_B + naive_plain_exp(this->Bt.begin()+1, this->Bt.begin()+1+this->num_variables(), + witness.coefficients_for_ABCs.begin(), witness.coefficients_for_ABCs.begin()+this->num_variables()); + ans_C = ans_C + naive_plain_exp(this->Ct.begin()+1, this->Ct.begin()+1+this->num_variables(), + witness.coefficients_for_ABCs.begin(), witness.coefficients_for_ABCs.begin()+this->num_variables()); + ans_H = ans_H + naive_plain_exp(this->Ht.begin(), this->Ht.begin()+this->degree()+1, + witness.coefficients_for_H.begin(), witness.coefficients_for_H.begin()+this->degree()+1); + + if (ans_A * ans_B - ans_C != ans_H * this->Zt) + { + return false; + } + + return true; +} + +template +qap_witness::qap_witness(const size_t num_variables, + const size_t degree, + const size_t num_inputs, + const FieldT &d1, + const FieldT &d2, + const FieldT &d3, + const std::vector &coefficients_for_ABCs, + const std::vector &coefficients_for_H) : + num_variables_(num_variables), + degree_(degree), + num_inputs_(num_inputs), + d1(d1), + d2(d2), + d3(d3), + coefficients_for_ABCs(coefficients_for_ABCs), + coefficients_for_H(coefficients_for_H) +{ +} + +template +qap_witness::qap_witness(const size_t num_variables, + const size_t degree, + const size_t num_inputs, + const FieldT &d1, + const FieldT &d2, + const FieldT &d3, + const std::vector &coefficients_for_ABCs, + std::vector &&coefficients_for_H) : + num_variables_(num_variables), + degree_(degree), + num_inputs_(num_inputs), + d1(d1), + d2(d2), + d3(d3), + coefficients_for_ABCs(coefficients_for_ABCs), + coefficients_for_H(std::move(coefficients_for_H)) +{ +} + + +template +size_t qap_witness::num_variables() const +{ + return num_variables_; +} + +template +size_t qap_witness::degree() const +{ + return degree_; +} + +template +size_t qap_witness::num_inputs() const +{ + return num_inputs_; +} + + +} // libsnark + +#endif // QAP_TCC_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/relations/arithmetic_programs/qap/tests/test_qap.cpp b/privacy/zsl/zsl/snark/libsnark/src/relations/arithmetic_programs/qap/tests/test_qap.cpp new file mode 100644 index 0000000..d8aadda --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/relations/arithmetic_programs/qap/tests/test_qap.cpp @@ -0,0 +1,115 @@ +/** + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ +#include +#include +#include +#include +#include + +#include "algebra/curves/mnt/mnt6/mnt6_pp.hpp" +#include "algebra/fields/field_utils.hpp" +#include "common/profiling.hpp" +#include "common/utils.hpp" +#include "reductions/r1cs_to_qap/r1cs_to_qap.hpp" +#include "relations/constraint_satisfaction_problems/r1cs/examples/r1cs_examples.hpp" + +using namespace libsnark; + +template +void test_qap(const size_t qap_degree, const size_t num_inputs, const bool binary_input) +{ + /* + We construct an instance where the QAP degree is qap_degree. + So we generate an instance of R1CS where the number of constraints qap_degree - num_inputs - 1. + See the transformation from R1CS to QAP for why this is the case. + So we need that qap_degree >= num_inputs + 1. + */ + assert(num_inputs + 1 <= qap_degree); + enter_block("Call to test_qap"); + + const size_t num_constraints = qap_degree - num_inputs - 1; + + print_indent(); printf("* QAP degree: %zu\n", qap_degree); + print_indent(); printf("* Number of inputs: %zu\n", num_inputs); + print_indent(); printf("* Number of R1CS constraints: %zu\n", num_constraints); + print_indent(); printf("* Input type: %s\n", binary_input ? "binary" : "field"); + + enter_block("Generate constraint system and assignment"); + r1cs_example example; + if (binary_input) + { + example = generate_r1cs_example_with_binary_input(num_constraints, num_inputs); + } + else + { + example = generate_r1cs_example_with_field_input(num_constraints, num_inputs); + } + leave_block("Generate constraint system and assignment"); + + enter_block("Check satisfiability of constraint system"); + assert(example.constraint_system.is_satisfied(example.primary_input, example.auxiliary_input)); + leave_block("Check satisfiability of constraint system"); + + const FieldT t = FieldT::random_element(), + d1 = FieldT::random_element(), + d2 = FieldT::random_element(), + d3 = FieldT::random_element(); + + enter_block("Compute QAP instance 1"); + qap_instance qap_inst_1 = r1cs_to_qap_instance_map(example.constraint_system); + leave_block("Compute QAP instance 1"); + + enter_block("Compute QAP instance 2"); + qap_instance_evaluation qap_inst_2 = r1cs_to_qap_instance_map_with_evaluation(example.constraint_system, t); + leave_block("Compute QAP instance 2"); + + enter_block("Compute QAP witness"); + qap_witness qap_wit = r1cs_to_qap_witness_map(example.constraint_system, example.primary_input, example.auxiliary_input, d1, d2, d3); + leave_block("Compute QAP witness"); + + enter_block("Check satisfiability of QAP instance 1"); + assert(qap_inst_1.is_satisfied(qap_wit)); + leave_block("Check satisfiability of QAP instance 1"); + + enter_block("Check satisfiability of QAP instance 2"); + assert(qap_inst_2.is_satisfied(qap_wit)); + leave_block("Check satisfiability of QAP instance 2"); + + leave_block("Call to test_qap"); +} + +int main() +{ + start_profiling(); + + mnt6_pp::init_public_params(); + + const size_t num_inputs = 10; + + const size_t basic_domain_size = 1ul< >(basic_domain_size, num_inputs, true); + test_qap >(step_domain_size, num_inputs, true); + test_qap >(extended_domain_size, num_inputs, true); + test_qap >(extended_domain_size_special, num_inputs, true); + + leave_block("Test QAP with binary input"); + + enter_block("Test QAP with field input"); + + test_qap >(basic_domain_size, num_inputs, false); + test_qap >(step_domain_size, num_inputs, false); + test_qap >(extended_domain_size, num_inputs, false); + test_qap >(extended_domain_size_special, num_inputs, false); + + leave_block("Test QAP with field input"); +} diff --git a/privacy/zsl/zsl/snark/libsnark/src/relations/arithmetic_programs/ssp/ssp.hpp b/privacy/zsl/zsl/snark/libsnark/src/relations/arithmetic_programs/ssp/ssp.hpp new file mode 100644 index 0000000..48ddd05 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/relations/arithmetic_programs/ssp/ssp.hpp @@ -0,0 +1,178 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for a SSP ("Square Span Program"). + + SSPs are defined in \[DFGK14]. + + References: + + \[DFGK14]: + "Square Span Programs with Applications to Succinct NIZK Arguments" + George Danezis, Cedric Fournet, Jens Groth, Markulf Kohlweiss, + ASIACRYPT 2014, + + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef SSP_HPP_ +#define SSP_HPP_ + +#include "algebra/evaluation_domain/evaluation_domain.hpp" + +namespace libsnark { + +/* forward declaration */ +template +class ssp_witness; + +/** + * A SSP instance. + * + * Specifically, the datastructure stores: + * - a choice of domain (corresponding to a certain subset of the field); + * - the number of variables, the degree, and the number of inputs; and + * - coefficients of the V polynomials in the Lagrange basis. + * + * There is no need to store the Z polynomial because it is uniquely + * determined by the domain (as Z is its vanishing polynomial). + */ +template +class ssp_instance { +private: + size_t num_variables_; + size_t degree_; + size_t num_inputs_; + +public: + std::shared_ptr > domain; + + std::vector > V_in_Lagrange_basis; + + ssp_instance(const std::shared_ptr > &domain, + const size_t num_variables, + const size_t degree, + const size_t num_inputs, + const std::vector > &V_in_Lagrange_basis); + ssp_instance(const std::shared_ptr > &domain, + const size_t num_variables, + const size_t degree, + const size_t num_inputs, + std::vector > &&V_in_Lagrange_basis); + + ssp_instance(const ssp_instance &other) = default; + ssp_instance(ssp_instance &&other) = default; + ssp_instance& operator=(const ssp_instance &other) = default; + ssp_instance& operator=(ssp_instance &&other) = default; + + size_t num_variables() const; + size_t degree() const; + size_t num_inputs() const; + + bool is_satisfied(const ssp_witness &witness) const; +}; + + +/** + * A SSP instance evaluation is a SSP instance that is evaluated at a field element t. + * + * Specifically, the datastructure stores: + * - a choice of domain (corresponding to a certain subset of the field); + * - the number of variables, the degree, and the number of inputs; + * - a field element t; + * - evaluations of the V (and Z) polynomials at t; + * - evaluations of all monomials of t. + */ +template +class ssp_instance_evaluation { +private: + size_t num_variables_; + size_t degree_; + size_t num_inputs_; + +public: + std::shared_ptr > domain; + + FieldT t; + + std::vector Vt, Ht; + + FieldT Zt; + + ssp_instance_evaluation(const std::shared_ptr > &domain, + const size_t num_variables, + const size_t degree, + const size_t num_inputs, + const FieldT &t, + const std::vector &Vt, + const std::vector &Ht, + const FieldT &Zt); + ssp_instance_evaluation(const std::shared_ptr > &domain, + const size_t num_variables, + const size_t degree, + const size_t num_inputs, + const FieldT &t, + std::vector &&Vt, + std::vector &&Ht, + const FieldT &Zt); + + ssp_instance_evaluation(const ssp_instance_evaluation &other) = default; + ssp_instance_evaluation(ssp_instance_evaluation &&other) = default; + ssp_instance_evaluation& operator=(const ssp_instance_evaluation &other) = default; + ssp_instance_evaluation& operator=(ssp_instance_evaluation &&other) = default; + + size_t num_variables() const; + size_t degree() const; + size_t num_inputs() const; + + bool is_satisfied(const ssp_witness &witness) const; +}; + +/** + * A SSP witness. + */ +template +class ssp_witness { +private: + size_t num_variables_; + size_t degree_; + size_t num_inputs_; + +public: + FieldT d; + + std::vector coefficients_for_Vs; + std::vector coefficients_for_H; + + ssp_witness(const size_t num_variables, + const size_t degree, + const size_t num_inputs, + const FieldT &d, + const std::vector &coefficients_for_Vs, + const std::vector &coefficients_for_H); + ssp_witness(const size_t num_variables, + const size_t degree, + const size_t num_inputs, + const FieldT &d, + const std::vector &coefficients_for_Vs, + std::vector &&coefficients_for_H); + + ssp_witness(const ssp_witness &other) = default; + ssp_witness(ssp_witness &&other) = default; + ssp_witness& operator=(const ssp_witness &other) = default; + ssp_witness& operator=(ssp_witness &&other) = default; + + size_t num_variables() const; + size_t degree() const; + size_t num_inputs() const; +}; + +} // libsnark + +#include "relations/arithmetic_programs/ssp/ssp.tcc" + +#endif // SSP_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/relations/arithmetic_programs/ssp/ssp.tcc b/privacy/zsl/zsl/snark/libsnark/src/relations/arithmetic_programs/ssp/ssp.tcc new file mode 100644 index 0000000..d0db747 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/relations/arithmetic_programs/ssp/ssp.tcc @@ -0,0 +1,277 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for a SSP ("Square Span Program"). + + See ssp.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef SSP_TCC_ +#define SSP_TCC_ + +#include "common/profiling.hpp" +#include "common/utils.hpp" +#include "algebra/evaluation_domain/evaluation_domain.hpp" +#include "algebra/scalar_multiplication/multiexp.hpp" + +namespace libsnark { + +template +ssp_instance::ssp_instance(const std::shared_ptr > &domain, + const size_t num_variables, + const size_t degree, + const size_t num_inputs, + const std::vector > &V_in_Lagrange_basis) : + num_variables_(num_variables), + degree_(degree), + num_inputs_(num_inputs), + domain(domain), + V_in_Lagrange_basis(V_in_Lagrange_basis) +{ +} + +template +ssp_instance::ssp_instance(const std::shared_ptr > &domain, + const size_t num_variables, + const size_t degree, + const size_t num_inputs, + std::vector > &&V_in_Lagrange_basis) : + num_variables_(num_variables), + degree_(degree), + num_inputs_(num_inputs), + domain(domain), + V_in_Lagrange_basis(std::move(V_in_Lagrange_basis)) +{ +} + +template +size_t ssp_instance::num_variables() const +{ + return num_variables_; +} + +template +size_t ssp_instance::degree() const +{ + return degree_; +} + +template +size_t ssp_instance::num_inputs() const +{ + return num_inputs_; +} + +template +bool ssp_instance::is_satisfied(const ssp_witness &witness) const +{ + const FieldT t = FieldT::random_element();; + std::vector Vt(this->num_variables()+1, FieldT::zero()); + std::vector Ht(this->degree()+1); + + const FieldT Zt = this->domain->compute_Z(t); + + const std::vector u = this->domain->lagrange_coeffs(t); + + for (size_t i = 0; i < this->num_variables()+1; ++i) + { + for (auto &el : V_in_Lagrange_basis[i]) + { + Vt[i] += u[el.first] * el.second; + } + } + + FieldT ti = FieldT::one(); + for (size_t i = 0; i < this->degree()+1; ++i) + { + Ht[i] = ti; + ti *= t; + } + + const ssp_instance_evaluation eval_ssp_inst(this->domain, + this->num_variables(), + this->degree(), + this->num_inputs(), + t, + std::move(Vt), + std::move(Ht), + Zt); + return eval_ssp_inst.is_satisfied(witness); +} + +template +ssp_instance_evaluation::ssp_instance_evaluation(const std::shared_ptr > &domain, + const size_t num_variables, + const size_t degree, + const size_t num_inputs, + const FieldT &t, + const std::vector &Vt, + const std::vector &Ht, + const FieldT &Zt) : + num_variables_(num_variables), + degree_(degree), + num_inputs_(num_inputs), + domain(domain), + t(t), + Vt(Vt), + Ht(Ht), + Zt(Zt) +{ +} + +template +ssp_instance_evaluation::ssp_instance_evaluation(const std::shared_ptr > &domain, + const size_t num_variables, + const size_t degree, + const size_t num_inputs, + const FieldT &t, + std::vector &&Vt, + std::vector &&Ht, + const FieldT &Zt) : + num_variables_(num_variables), + degree_(degree), + num_inputs_(num_inputs), + domain(domain), + t(t), + Vt(std::move(Vt)), + Ht(std::move(Ht)), + Zt(Zt) +{ +} + +template +size_t ssp_instance_evaluation::num_variables() const +{ + return num_variables_; +} + +template +size_t ssp_instance_evaluation::degree() const +{ + return degree_; +} + +template +size_t ssp_instance_evaluation::num_inputs() const +{ + return num_inputs_; +} + +template +bool ssp_instance_evaluation::is_satisfied(const ssp_witness &witness) const +{ + + if (this->num_variables() != witness.num_variables()) + { + return false; + } + + if (this->degree() != witness.degree()) + { + return false; + } + + if (this->num_inputs() != witness.num_inputs()) + { + return false; + } + + if (this->num_variables() != witness.coefficients_for_Vs.size()) + { + return false; + } + + if (this->degree()+1 != witness.coefficients_for_H.size()) + { + return false; + } + + if (this->Vt.size() != this->num_variables()+1) + { + return false; + } + + if (this->Ht.size() != this->degree()+1) + { + return false; + } + + if (this->Zt != this->domain->compute_Z(this->t)) + { + return false; + } + + FieldT ans_V = this->Vt[0] + witness.d*this->Zt; + FieldT ans_H = FieldT::zero(); + + ans_V = ans_V + naive_plain_exp(this->Vt.begin()+1, this->Vt.begin()+1+this->num_variables(), + witness.coefficients_for_Vs.begin(), witness.coefficients_for_Vs.begin()+this->num_variables()); + ans_H = ans_H + naive_plain_exp(this->Ht.begin(), this->Ht.begin()+this->degree()+1, + witness.coefficients_for_H.begin(), witness.coefficients_for_H.begin()+this->degree()+1); + + if (ans_V.squared() - FieldT::one() != ans_H * this->Zt) + { + return false; + } + + return true; +} + +template +ssp_witness::ssp_witness(const size_t num_variables, + const size_t degree, + const size_t num_inputs, + const FieldT &d, + const std::vector &coefficients_for_Vs, + const std::vector &coefficients_for_H) : + num_variables_(num_variables), + degree_(degree), + num_inputs_(num_inputs), + d(d), + coefficients_for_Vs(coefficients_for_Vs), + coefficients_for_H(coefficients_for_H) +{ +} + +template +ssp_witness::ssp_witness(const size_t num_variables, + const size_t degree, + const size_t num_inputs, + const FieldT &d, + const std::vector &coefficients_for_Vs, + std::vector &&coefficients_for_H) : + num_variables_(num_variables), + degree_(degree), + num_inputs_(num_inputs), + d(d), + coefficients_for_Vs(coefficients_for_Vs), + coefficients_for_H(std::move(coefficients_for_H)) +{ +} + +template +size_t ssp_witness::num_variables() const +{ + return num_variables_; +} + +template +size_t ssp_witness::degree() const +{ + return degree_; +} + +template +size_t ssp_witness::num_inputs() const +{ + return num_inputs_; +} + +} // libsnark + +#endif // SSP_TCC_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/relations/arithmetic_programs/ssp/tests/test_ssp.cpp b/privacy/zsl/zsl/snark/libsnark/src/relations/arithmetic_programs/ssp/tests/test_ssp.cpp new file mode 100644 index 0000000..a0eeeea --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/relations/arithmetic_programs/ssp/tests/test_ssp.cpp @@ -0,0 +1,103 @@ +/** + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ +#include +#include +#include +#include +#include + +#include "algebra/curves/mnt/mnt6/mnt6_pp.hpp" +#include "algebra/fields/field_utils.hpp" +#include "common/profiling.hpp" +#include "common/utils.hpp" +#include "reductions/uscs_to_ssp/uscs_to_ssp.hpp" +#include "relations/constraint_satisfaction_problems/uscs/examples/uscs_examples.hpp" + +using namespace libsnark; + +template +void test_ssp(const size_t num_constraints, const size_t num_inputs, const bool binary_input) +{ + enter_block("Call to test_ssp"); + + print_indent(); printf("* Number of constraints: %zu\n", num_constraints); + print_indent(); printf("* Number of inputs: %zu\n", num_inputs); + print_indent(); printf("* Input type: %s\n", binary_input ? "binary" : "field"); + + enter_block("Generate constraint system and assignment"); + uscs_example example; + if (binary_input) + { + example = generate_uscs_example_with_binary_input(num_constraints, num_inputs); + } + else + { + example = generate_uscs_example_with_field_input(num_constraints, num_inputs); + } + leave_block("Generate constraint system and assignment"); + + enter_block("Check satisfiability of constraint system"); + assert(example.constraint_system.is_satisfied(example.primary_input, example.auxiliary_input)); + leave_block("Check satisfiability of constraint system"); + + const FieldT t = FieldT::random_element(), + d = FieldT::random_element(); + + enter_block("Compute SSP instance 1"); + ssp_instance ssp_inst_1 = uscs_to_ssp_instance_map(example.constraint_system); + leave_block("Compute SSP instance 1"); + + enter_block("Compute SSP instance 2"); + ssp_instance_evaluation ssp_inst_2 = uscs_to_ssp_instance_map_with_evaluation(example.constraint_system, t); + leave_block("Compute SSP instance 2"); + + enter_block("Compute SSP witness"); + ssp_witness ssp_wit = uscs_to_ssp_witness_map(example.constraint_system, example.primary_input, example.auxiliary_input, d); + leave_block("Compute SSP witness"); + + enter_block("Check satisfiability of SSP instance 1"); + assert(ssp_inst_1.is_satisfied(ssp_wit)); + leave_block("Check satisfiability of SSP instance 1"); + + enter_block("Check satisfiability of SSP instance 2"); + assert(ssp_inst_2.is_satisfied(ssp_wit)); + leave_block("Check satisfiability of SSP instance 2"); + + leave_block("Call to test_ssp"); +} + +int main() +{ + start_profiling(); + + mnt6_pp::init_public_params(); + + const size_t num_inputs = 10; + + const size_t basic_domain_size = 1ul< >(basic_domain_size, num_inputs, true); + test_ssp >(step_domain_size, num_inputs, true); + test_ssp >(extended_domain_size, num_inputs, true); + test_ssp >(extended_domain_size_special, num_inputs, true); + + leave_block("Test SSP for binary inputs"); + + enter_block("Test SSP for field inputs"); + + test_ssp >(basic_domain_size, num_inputs, false); + test_ssp >(step_domain_size, num_inputs, false); + test_ssp >(extended_domain_size, num_inputs, false); + test_ssp >(extended_domain_size_special, num_inputs, false); + + leave_block("Test SSP for field inputs"); +} diff --git a/privacy/zsl/zsl/snark/libsnark/src/relations/circuit_satisfaction_problems/bacs/bacs.hpp b/privacy/zsl/zsl/snark/libsnark/src/relations/circuit_satisfaction_problems/bacs/bacs.hpp new file mode 100644 index 0000000..274c9ec --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/relations/circuit_satisfaction_problems/bacs/bacs.hpp @@ -0,0 +1,155 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for: + - a BACS variable assigment, + - a BACS gate, + - a BACS primary input, + - a BACS auxiliary input, + - a BACS circuit. + + Above, BACS stands for "Bilinear Arithmetic Circuit Satisfiability". + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef BACS_HPP_ +#define BACS_HPP_ + +#include + +#include "relations/variable.hpp" + +namespace libsnark { + +/*********************** BACS variable assignment ****************************/ + +/** + * A BACS variable assignment is a vector of field elements. + */ +template +using bacs_variable_assignment = std::vector; + + +/**************************** BACS gate **************************************/ + +template +struct bacs_gate; + +template +std::ostream& operator<<(std::ostream &out, const bacs_gate &g); + +template +std::istream& operator>>(std::istream &in, bacs_gate &g); + +/** + * A BACS gate is a formal expression of the form lhs * rhs = output , + * where lhs and rhs are linear combinations (of variables) and output is a variable. + * + * In other words, a BACS gate is an arithmetic gate that is bilinear. + */ +template +struct bacs_gate { + + linear_combination lhs; + linear_combination rhs; + + variable output; + bool is_circuit_output; + + FieldT evaluate(const bacs_variable_assignment &input) const; + void print(const std::map &variable_annotations = std::map()) const; + + bool operator==(const bacs_gate &other) const; + + friend std::ostream& operator<< (std::ostream &out, const bacs_gate &g); + friend std::istream& operator>> (std::istream &in, bacs_gate &g); +}; + + +/****************************** BACS inputs **********************************/ + +/** + * A BACS primary input is a BACS variable assignment. + */ +template +using bacs_primary_input = bacs_variable_assignment; + +/** + * A BACS auxiliary input is a BACS variable assigment. + */ +template +using bacs_auxiliary_input = bacs_variable_assignment; + + +/************************** BACS circuit *************************************/ + +template +class bacs_circuit; + +template +std::ostream& operator<<(std::ostream &out, const bacs_circuit &circuit); + +template +std::istream& operator>>(std::istream &in, bacs_circuit &circuit); + +/** + * A BACS circuit is an arithmetic circuit in which every gate is a BACS gate. + * + * Given a BACS primary input and a BACS auxiliary input, the circuit can be evaluated. + * If every output evaluates to zero, then the circuit is satisfied. + * + * NOTE: + * The 0-th variable (i.e., "x_{0}") always represents the constant 1. + * Thus, the 0-th variable is not included in num_variables. + */ +template +class bacs_circuit { +public: + size_t primary_input_size; + size_t auxiliary_input_size; + std::vector > gates; + + bacs_circuit() : primary_input_size(0), auxiliary_input_size(0) {} + + size_t num_inputs() const; + size_t num_gates() const; + size_t num_wires() const; + + std::vector wire_depths() const; + size_t depth() const; + +#ifdef DEBUG + std::map gate_annotations; + std::map variable_annotations; +#endif + + bool is_valid() const; + bool is_satisfied(const bacs_primary_input &primary_input, + const bacs_auxiliary_input &auxiliary_input) const; + + bacs_variable_assignment get_all_outputs(const bacs_primary_input &primary_input, + const bacs_auxiliary_input &auxiliary_input) const; + bacs_variable_assignment get_all_wires(const bacs_primary_input &primary_input, + const bacs_auxiliary_input &auxiliary_input) const; + + void add_gate(const bacs_gate &g); + void add_gate(const bacs_gate &g, const std::string &annotation); + + bool operator==(const bacs_circuit &other) const; + + void print() const; + void print_info() const; + + friend std::ostream& operator<< (std::ostream &out, const bacs_circuit &circuit); + friend std::istream& operator>> (std::istream &in, bacs_circuit &circuit); +}; + +} // libsnark + +#include "relations/circuit_satisfaction_problems/bacs/bacs.tcc" + +#endif // BACS_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/relations/circuit_satisfaction_problems/bacs/bacs.tcc b/privacy/zsl/zsl/snark/libsnark/src/relations/circuit_satisfaction_problems/bacs/bacs.tcc new file mode 100644 index 0000000..3aff51b --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/relations/circuit_satisfaction_problems/bacs/bacs.tcc @@ -0,0 +1,305 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for: + - a BACS variable assigment, + - a BACS gate, + - a BACS primary input, + - a BACS auxiliary input, + - a BACS circuit. + + See bacs.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef BACS_TCC_ +#define BACS_TCC_ + +#include +#include "common/profiling.hpp" +#include "common/utils.hpp" + +namespace libsnark { + +template +FieldT bacs_gate::evaluate(const bacs_variable_assignment &input) const +{ + return lhs.evaluate(input) * rhs.evaluate(input); +} + +template +void bacs_gate::print(const std::map &variable_annotations) const +{ + printf("(\n"); + lhs.print(variable_annotations); + printf(")\n *\n(\n"); + rhs.print(variable_annotations); + printf(")\n -> \n"); + auto it = variable_annotations.find(output.index); + printf(" x_%zu (%s) (%s)\n", + output.index, + (it == variable_annotations.end() ? "no annotation" : it->second.c_str()), + (is_circuit_output ? "circuit output" : "internal wire")); +} + +template +bool bacs_gate::operator==(const bacs_gate &other) const +{ + return (this->lhs == other.lhs && + this->rhs == other.rhs && + this->output == other.output && + this->is_circuit_output == other.is_circuit_output); +} + +template +std::ostream& operator<<(std::ostream &out, const bacs_gate &g) +{ + out << (g.is_circuit_output ? 1 : 0) << "\n"; + out << g.lhs << OUTPUT_NEWLINE; + out << g.rhs << OUTPUT_NEWLINE; + out << g.output.index << "\n"; + + return out; +} + +template +std::istream& operator>>(std::istream &in, bacs_gate &g) +{ + size_t tmp; + in >> tmp; + consume_newline(in); + g.is_circuit_output = (tmp != 0 ? true : false); + in >> g.lhs; + consume_OUTPUT_NEWLINE(in); + in >> g.rhs; + consume_OUTPUT_NEWLINE(in); + in >> g.output.index; + consume_newline(in); + + return in; +} + +template +size_t bacs_circuit::num_inputs() const +{ + return primary_input_size + auxiliary_input_size; +} + +template +size_t bacs_circuit::num_gates() const +{ + return gates.size(); +} + +template +size_t bacs_circuit::num_wires() const +{ + return num_inputs() + num_gates(); +} + +template +std::vector bacs_circuit::wire_depths() const +{ + std::vector depths; + depths.emplace_back(0); + depths.resize(num_inputs() + 1, 1); + + for (auto &g: gates) + { + size_t max_depth = 0; + for (auto &t : g.lhs) + { + max_depth = std::max(max_depth, depths[t.index]); + } + + for (auto &t : g.rhs) + { + max_depth = std::max(max_depth, depths[t.index]); + } + + depths.emplace_back(max_depth + 1); + } + + return depths; +} + +template +size_t bacs_circuit::depth() const +{ + std::vector all_depths = this->wire_depths(); + return *(std::max_element(all_depths.begin(), all_depths.end())); +} + +template +bool bacs_circuit::is_valid() const +{ + for (size_t i = 0; i < num_gates(); ++i) + { + /** + * The output wire of gates[i] must have index 1+num_inputs+i. + * (The '1+' accounts for the the index of the constant wire.) + */ + if (gates[i].output.index != 1+num_inputs()+i) + { + return false; + } + + /** + * Gates must be topologically sorted. + */ + if (!gates[i].lhs.is_valid(gates[i].output.index) || !gates[i].rhs.is_valid(gates[i].output.index)) + { + return false; + } + } + + return true; +} + +template +bacs_variable_assignment bacs_circuit::get_all_wires(const bacs_primary_input &primary_input, + const bacs_auxiliary_input &auxiliary_input) const +{ + assert(primary_input.size() == primary_input_size); + assert(auxiliary_input.size() == auxiliary_input_size); + + bacs_variable_assignment result; + result.insert(result.end(), primary_input.begin(), primary_input.end()); + result.insert(result.end(), auxiliary_input.begin(), auxiliary_input.end()); + + assert(result.size() == num_inputs()); + + for (auto &g : gates) + { + const FieldT gate_output = g.evaluate(result); + result.emplace_back(gate_output); + } + + return result; +} + +template +bacs_variable_assignment bacs_circuit::get_all_outputs(const bacs_primary_input &primary_input, + const bacs_auxiliary_input &auxiliary_input) const +{ + const bacs_variable_assignment all_wires = get_all_wires(primary_input, auxiliary_input); + + bacs_variable_assignment all_outputs; + + for (auto &g: gates) + { + if (g.is_circuit_output) + { + all_outputs.emplace_back(all_wires[g.output.index-1]); + } + } + + return all_outputs; +} + +template +bool bacs_circuit::is_satisfied(const bacs_primary_input &primary_input, + const bacs_auxiliary_input &auxiliary_input) const +{ + const bacs_variable_assignment all_outputs = get_all_outputs(primary_input, auxiliary_input); + + for (size_t i = 0; i < all_outputs.size(); ++i) + { + if (!all_outputs[i].is_zero()) + { + return false; + } + } + + return true; +} + +template +void bacs_circuit::add_gate(const bacs_gate &g) +{ + assert(g.output.index == num_wires()+1); + gates.emplace_back(g); +} + +template +void bacs_circuit::add_gate(const bacs_gate &g, const std::string &annotation) +{ + assert(g.output.index == num_wires()+1); + gates.emplace_back(g); +#ifdef DEBUG + gate_annotations[g.output.index] = annotation; +#endif +} + +template +bool bacs_circuit::operator==(const bacs_circuit &other) const +{ + return (this->primary_input_size == other.primary_input_size && + this->auxiliary_input_size == other.auxiliary_input_size && + this->gates == other.gates); +} + +template +std::ostream& operator<<(std::ostream &out, const bacs_circuit &circuit) +{ + out << circuit.primary_input_size << "\n"; + out << circuit.auxiliary_input_size << "\n"; + out << circuit.gates << OUTPUT_NEWLINE; + + return out; +} + +template +std::istream& operator>>(std::istream &in, bacs_circuit &circuit) +{ + in >> circuit.primary_input_size; + consume_newline(in); + in >> circuit.auxiliary_input_size; + consume_newline(in); + in >> circuit.gates; + consume_OUTPUT_NEWLINE(in); + + return in; +} + +template +void bacs_circuit::print() const +{ + print_indent(); printf("General information about the circuit:\n"); + this->print_info(); + print_indent(); printf("All gates:\n"); + for (size_t i = 0; i < gates.size(); ++i) + { + std::string annotation = "no annotation"; +#ifdef DEBUG + auto it = gate_annotations.find(i); + if (it != gate_annotations.end()) + { + annotation = it->second; + } +#endif + printf("Gate %zu (%s):\n", i, annotation.c_str()); +#ifdef DEBUG + gates[i].print(variable_annotations); +#else + gates[i].print(); +#endif + } +} + +template +void bacs_circuit::print_info() const +{ + print_indent(); printf("* Number of inputs: %zu\n", this->num_inputs()); + print_indent(); printf("* Number of gates: %zu\n", this->num_gates()); + print_indent(); printf("* Number of wires: %zu\n", this->num_wires()); + print_indent(); printf("* Depth: %zu\n", this->depth()); +} + +} // libsnark + +#endif // BACS_TCC_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/relations/circuit_satisfaction_problems/bacs/examples/bacs_examples.hpp b/privacy/zsl/zsl/snark/libsnark/src/relations/circuit_satisfaction_problems/bacs/examples/bacs_examples.hpp new file mode 100644 index 0000000..565cf4b --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/relations/circuit_satisfaction_problems/bacs/examples/bacs_examples.hpp @@ -0,0 +1,71 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for a BACS example, as well as functions to sample + BACS examples with prescribed parameters (according to some distribution). + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef BACS_EXAMPLES_HPP_ +#define BACS_EXAMPLES_HPP_ + +#include "relations/circuit_satisfaction_problems/bacs/bacs.hpp" + +namespace libsnark { + +/** + * A BACS example comprises a BACS circuit, BACS primary input, and BACS auxiliary input. + */ +template +struct bacs_example { + + bacs_circuit circuit; + bacs_primary_input primary_input; + bacs_auxiliary_input auxiliary_input; + + bacs_example() = default; + bacs_example(const bacs_example &other) = default; + bacs_example(const bacs_circuit &circuit, + const bacs_primary_input &primary_input, + const bacs_auxiliary_input &auxiliary_input) : + circuit(circuit), + primary_input(primary_input), + auxiliary_input(auxiliary_input) + {} + + bacs_example(bacs_circuit &&circuit, + bacs_primary_input &&primary_input, + bacs_auxiliary_input &&auxiliary_input) : + circuit(std::move(circuit)), + primary_input(std::move(primary_input)), + auxiliary_input(std::move(auxiliary_input)) + {} +}; + +/** + * Generate a BACS example such that: + * - the primary input has size primary_input_size; + * - the auxiliary input has size auxiliary_input_size; + * - the circuit has num_gates gates; + * - the circuit has num_outputs (<= num_gates) output gates. + * + * This is done by first selecting primary and auxiliary inputs uniformly at random, and then for each gate: + * - selecting random left and right wires from primary inputs, auxiliary inputs, and outputs of previous gates, + * - selecting random linear combinations for left and right wires, consisting of 1, 2, 3 or 4 terms each, with random coefficients, + * - if the gate is an output gate, then adding a random non-output wire to either left or right linear combination, with appropriate coefficient, so that the linear combination evaluates to 0. + */ +template +bacs_example generate_bacs_example(const size_t primary_input_size, + const size_t auxiliary_input_size, + const size_t num_gates, + const size_t num_outputs); + +} // libsnark + +#include "relations/circuit_satisfaction_problems/bacs/examples/bacs_examples.tcc" + +#endif // BACS_EXAMPLES_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/relations/circuit_satisfaction_problems/bacs/examples/bacs_examples.tcc b/privacy/zsl/zsl/snark/libsnark/src/relations/circuit_satisfaction_problems/bacs/examples/bacs_examples.tcc new file mode 100644 index 0000000..d4fca1f --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/relations/circuit_satisfaction_problems/bacs/examples/bacs_examples.tcc @@ -0,0 +1,109 @@ +/** @file + ***************************************************************************** + + Implementation of functions to sample BACS examples with prescribed parameters + (according to some distribution). + + See bacs_examples.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef BACS_EXAMPLES_TCC_ +#define BACS_EXAMPLES_TCC_ + +#include + +#include "common/utils.hpp" + +namespace libsnark { + +template +linear_combination random_linear_combination(const size_t num_variables) +{ + const size_t terms = 1 + (std::rand() % 3); + linear_combination result; + + for (size_t i = 0; i < terms; ++i) + { + const FieldT coeff = FieldT(std::rand()); // TODO: replace with FieldT::random_element(), when it becomes faster... + result = result + coeff * variable(std::rand() % (num_variables + 1)); + } + + return result; +} + +template +bacs_example generate_bacs_example(const size_t primary_input_size, + const size_t auxiliary_input_size, + const size_t num_gates, + const size_t num_outputs) +{ + bacs_example example; + for (size_t i = 0; i < primary_input_size; ++i) + { + example.primary_input.emplace_back(FieldT::random_element()); + } + + for (size_t i = 0; i < auxiliary_input_size; ++i) + { + example.auxiliary_input.emplace_back(FieldT::random_element()); + } + + example.circuit.primary_input_size = primary_input_size; + example.circuit.auxiliary_input_size = auxiliary_input_size; + + bacs_variable_assignment all_vals; + all_vals.insert(all_vals.end(), example.primary_input.begin(), example.primary_input.end()); + all_vals.insert(all_vals.end(), example.auxiliary_input.begin(), example.auxiliary_input.end()); + + for (size_t i = 0; i < num_gates; ++i) + { + const size_t num_variables = primary_input_size + auxiliary_input_size + i; + bacs_gate gate; + gate.lhs = random_linear_combination(num_variables); + gate.rhs = random_linear_combination(num_variables); + gate.output = variable(num_variables+1); + + if (i >= num_gates - num_outputs) + { + /* make gate a circuit output and fix */ + gate.is_circuit_output = true; + const var_index_t var_idx = std::rand() % (1 + primary_input_size + std::min(num_gates-num_outputs, i)); + const FieldT var_val = (var_idx == 0 ? FieldT::one() : all_vals[var_idx-1]); + + if (std::rand() % 2 == 0) + { + const FieldT lhs_val = gate.lhs.evaluate(all_vals); + const FieldT coeff = -(lhs_val * var_val.inverse()); + gate.lhs = gate.lhs + coeff * variable(var_idx); + } + else + { + const FieldT rhs_val = gate.rhs.evaluate(all_vals); + const FieldT coeff = -(rhs_val * var_val.inverse()); + gate.rhs = gate.rhs + coeff * variable(var_idx); + } + + assert(gate.evaluate(all_vals).is_zero()); + } + else + { + gate.is_circuit_output = false; + } + + example.circuit.add_gate(gate); + all_vals.emplace_back(gate.evaluate(all_vals)); + } + + assert(example.circuit.is_satisfied(example.primary_input, example.auxiliary_input)); + + return example; +} + +} // libsnark + +#endif // BACS_EXAMPLES_TCC diff --git a/privacy/zsl/zsl/snark/libsnark/src/relations/circuit_satisfaction_problems/tbcs/examples/tbcs_examples.cpp b/privacy/zsl/zsl/snark/libsnark/src/relations/circuit_satisfaction_problems/tbcs/examples/tbcs_examples.cpp new file mode 100644 index 0000000..c8e703e --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/relations/circuit_satisfaction_problems/tbcs/examples/tbcs_examples.cpp @@ -0,0 +1,80 @@ +/** @file + ***************************************************************************** + + Implementation of functions to sample TBCS examples with prescribed parameters + (according to some distribution). + + See tbcs_examples.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include "relations/circuit_satisfaction_problems/tbcs/examples/tbcs_examples.hpp" + +#include + +#include "common/utils.hpp" + +namespace libsnark { + +tbcs_example generate_tbcs_example(const size_t primary_input_size, + const size_t auxiliary_input_size, + const size_t num_gates, + const size_t num_outputs) +{ + tbcs_example example; + for (size_t i = 0; i < primary_input_size; ++i) + { + example.primary_input.push_back(std::rand() % 2 == 0 ? false : true); + } + + for (size_t i = 0; i < auxiliary_input_size; ++i) + { + example.auxiliary_input.push_back(std::rand() % 2 == 0 ? false : true); + } + + example.circuit.primary_input_size = primary_input_size; + example.circuit.auxiliary_input_size = auxiliary_input_size; + + tbcs_variable_assignment all_vals; + all_vals.insert(all_vals.end(), example.primary_input.begin(), example.primary_input.end()); + all_vals.insert(all_vals.end(), example.auxiliary_input.begin(), example.auxiliary_input.end()); + + for (size_t i = 0; i < num_gates; ++i) + { + const size_t num_variables = primary_input_size + auxiliary_input_size + i; + tbcs_gate gate; + gate.left_wire = std::rand() % (num_variables+1); + gate.right_wire = std::rand() % (num_variables+1); + gate.output = num_variables+1; + + if (i >= num_gates - num_outputs) + { + /* make gate a circuit output and fix */ + do + { + gate.type = (tbcs_gate_type)(std::rand() % num_tbcs_gate_types); + } + while (gate.evaluate(all_vals)); + + gate.is_circuit_output = true; + } + else + { + gate.type = (tbcs_gate_type)(std::rand() % num_tbcs_gate_types); + gate.is_circuit_output = false; + } + + example.circuit.add_gate(gate); + all_vals.push_back(gate.evaluate(all_vals)); + } + + assert(example.circuit.is_satisfied(example.primary_input, example.auxiliary_input)); + + return example; +} + +} // libsnark diff --git a/privacy/zsl/zsl/snark/libsnark/src/relations/circuit_satisfaction_problems/tbcs/examples/tbcs_examples.hpp b/privacy/zsl/zsl/snark/libsnark/src/relations/circuit_satisfaction_problems/tbcs/examples/tbcs_examples.hpp new file mode 100644 index 0000000..f236f74 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/relations/circuit_satisfaction_problems/tbcs/examples/tbcs_examples.hpp @@ -0,0 +1,66 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for a TBCS example, as well as functions to sample + TBCS examples with prescribed parameters (according to some distribution). + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef TBCS_EXAMPLES_HPP_ +#define TBCS_EXAMPLES_HPP_ + +#include "relations/circuit_satisfaction_problems/tbcs/tbcs.hpp" + +namespace libsnark { + +/** + * A TBCS example comprises a TBCS circuit, TBCS primary input, and TBCS auxiliary input. + */ +struct tbcs_example { + + tbcs_circuit circuit; + tbcs_primary_input primary_input; + tbcs_auxiliary_input auxiliary_input; + + tbcs_example() = default; + tbcs_example(const tbcs_example &other) = default; + tbcs_example(const tbcs_circuit &circuit, + const tbcs_primary_input &primary_input, + const tbcs_auxiliary_input &auxiliary_input) : + circuit(circuit), + primary_input(primary_input), + auxiliary_input(auxiliary_input) + {} + + tbcs_example(tbcs_circuit &&circuit, + tbcs_primary_input &&primary_input, + tbcs_auxiliary_input &&auxiliary_input) : + circuit(std::move(circuit)), + primary_input(std::move(primary_input)), + auxiliary_input(std::move(auxiliary_input)) + {} +}; + +/** + * Generate a TBCS example such that: + * - the primary input has size primary_input_size; + * - the auxiliary input has size auxiliary_input_size; + * - the circuit has num_gates gates; + * - the circuit has num_outputs (<= num_gates) output gates. + * + * This is done by first selecting primary and auxiliary inputs uniformly at random, and then for each gate: + * - selecting random left and right wires from primary inputs, auxiliary inputs, and outputs of previous gates, + * - selecting a gate type at random (subject to the constraint "output = 0" if this is an output gate). + */ +tbcs_example generate_tbcs_example(const size_t primary_input_size, + const size_t auxiliary_input_size, + const size_t num_gates, + const size_t num_outputs); + +} // libsnark + +#endif // TBCS_EXAMPLES_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/relations/circuit_satisfaction_problems/tbcs/tbcs.cpp b/privacy/zsl/zsl/snark/libsnark/src/relations/circuit_satisfaction_problems/tbcs/tbcs.cpp new file mode 100644 index 0000000..599c0ae --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/relations/circuit_satisfaction_problems/tbcs/tbcs.cpp @@ -0,0 +1,348 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for: + - a TBCS gate, + - a TBCS variable assignment, and + - a TBCS constraint system. + + See tbcs.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include "relations/circuit_satisfaction_problems/tbcs/tbcs.hpp" + +#include +#include "common/utils.hpp" + +namespace libsnark { + +bool tbcs_gate::evaluate(const tbcs_variable_assignment &input) const +{ + /** + * This function is very tricky. + * See comment in tbcs.hpp . + */ + + const bool X = (left_wire == 0 ? true : input[left_wire - 1]); + const bool Y = (right_wire == 0 ? true : input[right_wire - 1]); + + const size_t pos = 3 - ((X ? 2 : 0) + (Y ? 1 : 0)); /* 3 - ... inverts position */ + + return (((int)type) & (1u << pos)); +} + +void print_tbcs_wire(const tbcs_wire_t wire, const std::map &variable_annotations) +{ + /** + * The type tbcs_wire_t does not deserve promotion to a class, + * but still benefits from a dedicated printing mechanism. + */ + if (wire == 0) + { + printf(" 1"); + } + else + { + auto it = variable_annotations.find(wire); + printf(" x_%zu (%s)", + wire, + (it == variable_annotations.end() ? "no annotation" : it->second.c_str())); + } +} + +void tbcs_gate::print(const std::map &variable_annotations) const +{ + switch (this->type) + { + case TBCS_GATE_CONSTANT_0: + printf("CONSTANT_0"); + break; + case TBCS_GATE_AND: + printf("AND"); + break; + case TBCS_GATE_X_AND_NOT_Y: + printf("X_AND_NOT_Y"); + break; + case TBCS_GATE_X: + printf("X"); + break; + case TBCS_GATE_NOT_X_AND_Y: + printf("NOT_X_AND_Y"); + break; + case TBCS_GATE_Y: + printf("Y"); + break; + case TBCS_GATE_XOR: + printf("XOR"); + break; + case TBCS_GATE_OR: + printf("OR"); + break; + case TBCS_GATE_NOR: + printf("NOR"); + break; + case TBCS_GATE_EQUIVALENCE: + printf("EQUIVALENCE"); + break; + case TBCS_GATE_NOT_Y: + printf("NOT_Y"); + break; + case TBCS_GATE_IF_Y_THEN_X: + printf("IF_Y_THEN_X"); + break; + case TBCS_GATE_NOT_X: + printf("NOT_X"); + break; + case TBCS_GATE_IF_X_THEN_Y: + printf("IF_X_THEN_Y"); + break; + case TBCS_GATE_NAND: + printf("NAND"); + break; + case TBCS_GATE_CONSTANT_1: + printf("CONSTANT_1"); + break; + default: + printf("Invalid type"); + } + + printf("\n(\n"); + print_tbcs_wire(left_wire, variable_annotations); + printf(",\n"); + print_tbcs_wire(right_wire, variable_annotations); + printf("\n) ->\n"); + print_tbcs_wire(output, variable_annotations); + printf(" (%s)\n", is_circuit_output ? "circuit output" : "internal wire"); +} + +bool tbcs_gate::operator==(const tbcs_gate &other) const +{ + return (this->left_wire == other.left_wire && + this->right_wire == other.right_wire && + this->type == other.type && + this->output == other.output && + this->is_circuit_output == other.is_circuit_output); +} + +std::ostream& operator<<(std::ostream &out, const tbcs_gate &g) +{ + out << g.left_wire << "\n"; + out << g.right_wire << "\n"; + out << (int)g.type << "\n"; + out << g.output << "\n"; + output_bool(out, g.is_circuit_output); + + return out; +} + +std::istream& operator>>(std::istream &in, tbcs_gate &g) +{ + in >> g.left_wire; + consume_newline(in); + in >> g.right_wire; + consume_newline(in); + int tmp; + in >> tmp; + g.type = (tbcs_gate_type)tmp; + consume_newline(in); + in >> g.output; + input_bool(in, g.is_circuit_output); + + return in; +} + +std::vector tbcs_circuit::wire_depths() const +{ + std::vector depths(num_inputs(), 1); + + for (auto &g: gates) + { + depths.emplace_back(std::max(depths[g.left_wire], depths[g.right_wire]) + 1); + } + + return depths; +} + +size_t tbcs_circuit::num_inputs() const +{ + return primary_input_size + auxiliary_input_size; +} + +size_t tbcs_circuit::num_gates() const +{ + return gates.size(); +} + +size_t tbcs_circuit::num_wires() const +{ + return num_inputs() + num_gates(); +} + +size_t tbcs_circuit::depth() const +{ + std::vector all_depths = this->wire_depths(); + return *(std::max_element(all_depths.begin(), all_depths.end())); +} + +bool tbcs_circuit::is_valid() const +{ + for (size_t i = 0; i < num_gates(); ++i) + { + /** + * The output wire of gates[i] must have index 1+num_inputs+i. + * (The '1+' accounts for the the index of the constant wire.) + */ + if (gates[i].output != num_inputs()+i+1) + { + return false; + } + + /** + * Gates must be topologically sorted. + */ + if (gates[i].left_wire >= gates[i].output || gates[i].right_wire >= gates[i].output) + { + return false; + } + } + + return true; +} + +tbcs_variable_assignment tbcs_circuit::get_all_wires(const tbcs_primary_input &primary_input, + const tbcs_auxiliary_input &auxiliary_input) const +{ + assert(primary_input.size() == primary_input_size); + assert(auxiliary_input.size() == auxiliary_input_size); + + tbcs_variable_assignment result; + result.insert(result.end(), primary_input.begin(), primary_input.end()); + result.insert(result.end(), auxiliary_input.begin(), auxiliary_input.end()); + + assert(result.size() == num_inputs()); + + for (auto &g : gates) + { + const bool gate_output = g.evaluate(result); + result.push_back(gate_output); + } + + return result; +} + +tbcs_variable_assignment tbcs_circuit::get_all_outputs(const tbcs_primary_input &primary_input, + const tbcs_auxiliary_input &auxiliary_input) const +{ + const tbcs_variable_assignment all_wires = get_all_wires(primary_input, auxiliary_input); + tbcs_variable_assignment all_outputs; + + for (auto &g : gates) + { + if (g.is_circuit_output) + { + all_outputs.push_back(all_wires[g.output-1]); + } + } + + return all_outputs; +} + + +bool tbcs_circuit::is_satisfied(const tbcs_primary_input &primary_input, + const tbcs_auxiliary_input &auxiliary_input) const +{ + const tbcs_variable_assignment all_outputs = get_all_outputs(primary_input, auxiliary_input); + for (size_t i = 0; i < all_outputs.size(); ++i) + { + if (all_outputs[i]) + { + return false; + } + } + + return true; +} + +void tbcs_circuit::add_gate(const tbcs_gate &g) +{ + assert(g.output == num_wires()+1); + gates.emplace_back(g); +} + +void tbcs_circuit::add_gate(const tbcs_gate &g, const std::string &annotation) +{ + assert(g.output == num_wires()+1); + gates.emplace_back(g); +#ifdef DEBUG + gate_annotations[g.output] = annotation; +#else + UNUSED(annotation); +#endif +} + +bool tbcs_circuit::operator==(const tbcs_circuit &other) const +{ + return (this->primary_input_size == other.primary_input_size && + this->auxiliary_input_size == other.auxiliary_input_size && + this->gates == other.gates); +} + +std::ostream& operator<<(std::ostream &out, const tbcs_circuit &circuit) +{ + out << circuit.primary_input_size << "\n"; + out << circuit.auxiliary_input_size << "\n"; + out << circuit.gates << OUTPUT_NEWLINE; + + return out; +} + +std::istream& operator>>(std::istream &in, tbcs_circuit &circuit) +{ + in >> circuit.primary_input_size; + consume_newline(in); + in >> circuit.auxiliary_input_size; + consume_newline(in); + in >> circuit.gates; + consume_OUTPUT_NEWLINE(in); + + return in; +} + +void tbcs_circuit::print() const +{ + print_indent(); printf("General information about the circuit:\n"); + this->print_info(); + print_indent(); printf("All gates:\n"); + for (size_t i = 0; i < gates.size(); ++i) + { + std::string annotation = "no annotation"; +#ifdef DEBUG + auto it = gate_annotations.find(i); + if (it != gate_annotations.end()) + { + annotation = it->second; + } +#endif + printf("Gate %zu (%s):\n", i, annotation.c_str()); +#ifdef DEBUG + gates[i].print(variable_annotations); +#else + gates[i].print(); +#endif + } +} + +void tbcs_circuit::print_info() const +{ + print_indent(); printf("* Number of inputs: %zu\n", this->num_inputs()); + print_indent(); printf("* Number of gates: %zu\n", this->num_gates()); + print_indent(); printf("* Number of wires: %zu\n", this->num_wires()); + print_indent(); printf("* Depth: %zu\n", this->depth()); +} + +} // libsnark diff --git a/privacy/zsl/zsl/snark/libsnark/src/relations/circuit_satisfaction_problems/tbcs/tbcs.hpp b/privacy/zsl/zsl/snark/libsnark/src/relations/circuit_satisfaction_problems/tbcs/tbcs.hpp new file mode 100644 index 0000000..cc1f96f --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/relations/circuit_satisfaction_problems/tbcs/tbcs.hpp @@ -0,0 +1,175 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for: + - a TBCS gate, + - a TBCS variable assignment, and + - a TBCS circuit. + + Above, TBCS stands for "Two-input Boolean Circuit Satisfiability". + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef TBCS_HPP_ +#define TBCS_HPP_ + +#include "common/profiling.hpp" +#include "relations/variable.hpp" + +namespace libsnark { + +/*********************** BACS variable assignment ****************************/ + +/** + * A TBCS variable assignment is a vector of bools. + */ +typedef std::vector tbcs_variable_assignment; + + +/**************************** TBCS gate **************************************/ + +typedef size_t tbcs_wire_t; + +/** + * Types of TBCS gates (2-input boolean gates). + * + * The order and names used below is taken from page 4 of [1]. + * + * Note that each gate's truth table is encoded in its 4-bit opcode. Namely, + * if g(X,Y) denotes the output of gate g with inputs X and Y, then + * OPCODE(g) = (g(0,0),g(0,1),g(1,0),g(1,1)) + * For example, if g is of type IF_X_THEN_Y, which has opcode 13, then the + * truth table of g is 1101 (13 in binary). + * + * (Note that MSB above is g(0,0) and LSB is g(1,1)) + * + * References: + * + * [1] = https://mitpress.mit.edu/sites/default/files/titles/content/9780262640688_sch_0001.pdf + */ +enum tbcs_gate_type { + TBCS_GATE_CONSTANT_0 = 0, + TBCS_GATE_AND = 1, + TBCS_GATE_X_AND_NOT_Y = 2, + TBCS_GATE_X = 3, + TBCS_GATE_NOT_X_AND_Y = 4, + TBCS_GATE_Y = 5, + TBCS_GATE_XOR = 6, + TBCS_GATE_OR = 7, + TBCS_GATE_NOR = 8, + TBCS_GATE_EQUIVALENCE = 9, + TBCS_GATE_NOT_Y = 10, + TBCS_GATE_IF_Y_THEN_X = 11, + TBCS_GATE_NOT_X = 12, + TBCS_GATE_IF_X_THEN_Y = 13, + TBCS_GATE_NAND = 14, + TBCS_GATE_CONSTANT_1 = 15 +}; + +static const int num_tbcs_gate_types = 16; + +/** + * A TBCS gate is a formal expression of the form + * + * g(left_wire,right_wire) = output , + * + * where 'left_wire' and 'right_wire' are the two input wires, and 'output' is + * the output wire. In other words, a TBCS gate is a 2-input boolean gate; + * there are 16 possible such gates (see tbcs_gate_type above). + * + * A TBCS gate is used to construct a TBCS circuit (see below). + */ +class tbcs_gate { +public: + + tbcs_wire_t left_wire; + tbcs_wire_t right_wire; + + tbcs_gate_type type; + + tbcs_wire_t output; + + bool is_circuit_output; + + bool evaluate(const tbcs_variable_assignment &input) const; + void print(const std::map &variable_annotations = std::map()) const; + bool operator==(const tbcs_gate &other) const; + + friend std::ostream& operator<<(std::ostream &out, const tbcs_gate &g); + friend std::istream& operator>>(std::istream &in, tbcs_gate &g); +}; + + +/****************************** TBCS inputs **********************************/ + +/** + * A TBCS primary input is a TBCS variable assignment. + */ +typedef tbcs_variable_assignment tbcs_primary_input; + +/** + * A TBCS auxiliary input is a TBCS variable assigment. + */ +typedef tbcs_variable_assignment tbcs_auxiliary_input; + + +/************************** TBCS circuit *************************************/ + +/** + * A TBCS circuit is a boolean circuit in which every gate has 2 inputs. + * + * A TBCS circuit is satisfied by a TBCS variable assignment if every output + * evaluates to zero. + * + * NOTE: + * The 0-th variable (i.e., "x_{0}") always represents the constant 1. + * Thus, the 0-th variable is not included in num_variables. + */ +class tbcs_circuit { +public: + size_t primary_input_size; + size_t auxiliary_input_size; + std::vector gates; + + tbcs_circuit() : primary_input_size(0), auxiliary_input_size(0) {} + + size_t num_inputs() const; + size_t num_gates() const; + size_t num_wires() const; + + std::vector wire_depths() const; + size_t depth() const; + +#ifdef DEBUG + std::map gate_annotations; + std::map variable_annotations; +#endif + + bool is_valid() const; + bool is_satisfied(const tbcs_primary_input &primary_input, + const tbcs_auxiliary_input &auxiliary_input) const; + + tbcs_variable_assignment get_all_wires(const tbcs_primary_input &primary_input, + const tbcs_auxiliary_input &auxiliary_input) const; + tbcs_variable_assignment get_all_outputs(const tbcs_primary_input &primary_input, + const tbcs_auxiliary_input &auxiliary_input) const; + + void add_gate(const tbcs_gate &g); + void add_gate(const tbcs_gate &g, const std::string &annotation); + + bool operator==(const tbcs_circuit &other) const; + + void print() const; + void print_info() const; + + friend std::ostream& operator<<(std::ostream &out, const tbcs_circuit &circuit); + friend std::istream& operator>>(std::istream &in, tbcs_circuit &circuit); +}; + +} // libsnark + +#endif // TBCS_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/relations/constraint_satisfaction_problems/r1cs/examples/r1cs_examples.hpp b/privacy/zsl/zsl/snark/libsnark/src/relations/constraint_satisfaction_problems/r1cs/examples/r1cs_examples.hpp new file mode 100644 index 0000000..47003e9 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/relations/constraint_satisfaction_problems/r1cs/examples/r1cs_examples.hpp @@ -0,0 +1,73 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for a R1CS example, as well as functions to sample + R1CS examples with prescribed parameters (according to some distribution). + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef R1CS_EXAMPLES_HPP_ +#define R1CS_EXAMPLES_HPP_ + +#include "relations/constraint_satisfaction_problems/r1cs/r1cs.hpp" + +namespace libsnark { + +/** + * A R1CS example comprises a R1CS constraint system, R1CS input, and R1CS witness. + */ +template +struct r1cs_example { + r1cs_constraint_system constraint_system; + r1cs_primary_input primary_input; + r1cs_auxiliary_input auxiliary_input; + + r1cs_example() = default; + r1cs_example(const r1cs_example &other) = default; + r1cs_example(const r1cs_constraint_system &constraint_system, + const r1cs_primary_input &primary_input, + const r1cs_auxiliary_input &auxiliary_input) : + constraint_system(constraint_system), + primary_input(primary_input), + auxiliary_input(auxiliary_input) + {}; + r1cs_example(r1cs_constraint_system &&constraint_system, + r1cs_primary_input &&primary_input, + r1cs_auxiliary_input &&auxiliary_input) : + constraint_system(std::move(constraint_system)), + primary_input(std::move(primary_input)), + auxiliary_input(std::move(auxiliary_input)) + {}; +}; + +/** + * Generate a R1CS example such that: + * - the number of constraints of the R1CS constraint system is num_constraints; + * - the number of variables of the R1CS constraint system is (approximately) num_constraints; + * - the number of inputs of the R1CS constraint system is num_inputs; + * - the R1CS input consists of ``full'' field elements (typically require the whole log|Field| bits to represent). + */ +template +r1cs_example generate_r1cs_example_with_field_input(const size_t num_constraints, + const size_t num_inputs); + +/** + * Generate a R1CS example such that: + * - the number of constraints of the R1CS constraint system is num_constraints; + * - the number of variables of the R1CS constraint system is (approximately) num_constraints; + * - the number of inputs of the R1CS constraint system is num_inputs; + * - the R1CS input consists of binary values (as opposed to ``full'' field elements). + */ +template +r1cs_example generate_r1cs_example_with_binary_input(const size_t num_constraints, + const size_t num_inputs); + +} // libsnark + +#include "relations/constraint_satisfaction_problems/r1cs/examples/r1cs_examples.tcc" + +#endif // R1CS_EXAMPLES_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/relations/constraint_satisfaction_problems/r1cs/examples/r1cs_examples.tcc b/privacy/zsl/zsl/snark/libsnark/src/relations/constraint_satisfaction_problems/r1cs/examples/r1cs_examples.tcc new file mode 100644 index 0000000..defa077 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/relations/constraint_satisfaction_problems/r1cs/examples/r1cs_examples.tcc @@ -0,0 +1,164 @@ +/** @file + ***************************************************************************** + + Implementation of functions to sample R1CS examples with prescribed parameters + (according to some distribution). + + See r1cs_examples.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef R1CS_EXAMPLES_TCC_ +#define R1CS_EXAMPLES_TCC_ + +#include + +#include "common/utils.hpp" + +namespace libsnark { + +template +r1cs_example generate_r1cs_example_with_field_input(const size_t num_constraints, + const size_t num_inputs) +{ + enter_block("Call to generate_r1cs_example_with_field_input"); + + assert(num_inputs <= num_constraints + 2); + + r1cs_constraint_system cs; + cs.primary_input_size = num_inputs; + cs.auxiliary_input_size = 2 + num_constraints - num_inputs; // TODO: explain this + + r1cs_variable_assignment full_variable_assignment; + FieldT a = FieldT::random_element(); + FieldT b = FieldT::random_element(); + full_variable_assignment.push_back(a); + full_variable_assignment.push_back(b); + + for (size_t i = 0; i < num_constraints-1; ++i) + { + linear_combination A, B, C; + + if (i % 2) + { + // a * b = c + A.add_term(i+1, 1); + B.add_term(i+2, 1); + C.add_term(i+3, 1); + FieldT tmp = a*b; + full_variable_assignment.push_back(tmp); + a = b; b = tmp; + } + else + { + // a + b = c + B.add_term(0, 1); + A.add_term(i+1, 1); + A.add_term(i+2, 1); + C.add_term(i+3, 1); + FieldT tmp = a+b; + full_variable_assignment.push_back(tmp); + a = b; b = tmp; + } + + cs.add_constraint(r1cs_constraint(A, B, C)); + } + + linear_combination A, B, C; + FieldT fin = FieldT::zero(); + for (size_t i = 1; i < cs.num_variables(); ++i) + { + A.add_term(i, 1); + B.add_term(i, 1); + fin = fin + full_variable_assignment[i-1]; + } + C.add_term(cs.num_variables(), 1); + cs.add_constraint(r1cs_constraint(A, B, C)); + full_variable_assignment.push_back(fin.squared()); + + /* split variable assignment */ + r1cs_primary_input primary_input(full_variable_assignment.begin(), full_variable_assignment.begin() + num_inputs); + r1cs_primary_input auxiliary_input(full_variable_assignment.begin() + num_inputs, full_variable_assignment.end()); + + /* sanity checks */ + assert(cs.num_variables() == full_variable_assignment.size()); + assert(cs.num_variables() >= num_inputs); + assert(cs.num_inputs() == num_inputs); + assert(cs.num_constraints() == num_constraints); + assert(cs.is_satisfied(primary_input, auxiliary_input)); + + leave_block("Call to generate_r1cs_example_with_field_input"); + + return r1cs_example(std::move(cs), std::move(primary_input), std::move(auxiliary_input)); +} + +template +r1cs_example generate_r1cs_example_with_binary_input(const size_t num_constraints, + const size_t num_inputs) +{ + enter_block("Call to generate_r1cs_example_with_binary_input"); + + assert(num_inputs >= 1); + + r1cs_constraint_system cs; + cs.primary_input_size = num_inputs; + cs.auxiliary_input_size = num_constraints; /* we will add one auxiliary variable per constraint */ + + r1cs_variable_assignment full_variable_assignment; + for (size_t i = 0; i < num_inputs; ++i) + { + full_variable_assignment.push_back(FieldT(std::rand() % 2)); + } + + size_t lastvar = num_inputs-1; + for (size_t i = 0; i < num_constraints; ++i) + { + ++lastvar; + const size_t u = (i == 0 ? std::rand() % num_inputs : std::rand() % i); + const size_t v = (i == 0 ? std::rand() % num_inputs : std::rand() % i); + + /* chose two random bits and XOR them together: + res = u + v - 2 * u * v + 2 * u * v = u + v - res + */ + linear_combination A, B, C; + A.add_term(u+1, 2); + B.add_term(v+1, 1); + if (u == v) + { + C.add_term(u+1, 2); + } + else + { + C.add_term(u+1, 1); + C.add_term(v+1, 1); + } + C.add_term(lastvar+1, -FieldT::one()); + + cs.add_constraint(r1cs_constraint(A, B, C)); + full_variable_assignment.push_back(full_variable_assignment[u] + full_variable_assignment[v] - full_variable_assignment[u] * full_variable_assignment[v] - full_variable_assignment[u] * full_variable_assignment[v]); + } + + /* split variable assignment */ + r1cs_primary_input primary_input(full_variable_assignment.begin(), full_variable_assignment.begin() + num_inputs); + r1cs_primary_input auxiliary_input(full_variable_assignment.begin() + num_inputs, full_variable_assignment.end()); + + /* sanity checks */ + assert(cs.num_variables() == full_variable_assignment.size()); + assert(cs.num_variables() >= num_inputs); + assert(cs.num_inputs() == num_inputs); + assert(cs.num_constraints() == num_constraints); + assert(cs.is_satisfied(primary_input, auxiliary_input)); + + leave_block("Call to generate_r1cs_example_with_binary_input"); + + return r1cs_example(std::move(cs), std::move(primary_input), std::move(auxiliary_input)); +} + +} // libsnark + +#endif // R1CS_EXAMPLES_TCC diff --git a/privacy/zsl/zsl/snark/libsnark/src/relations/constraint_satisfaction_problems/r1cs/r1cs.hpp b/privacy/zsl/zsl/snark/libsnark/src/relations/constraint_satisfaction_problems/r1cs/r1cs.hpp new file mode 100644 index 0000000..ca3acb3 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/relations/constraint_satisfaction_problems/r1cs/r1cs.hpp @@ -0,0 +1,153 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for: + - a R1CS constraint, + - a R1CS variable assignment, and + - a R1CS constraint system. + + Above, R1CS stands for "Rank-1 Constraint System". + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef R1CS_HPP_ +#define R1CS_HPP_ + +#include +#include +#include +#include +#include + +#include "relations/variable.hpp" + +namespace libsnark { + +/************************* R1CS constraint ***********************************/ + +template +class r1cs_constraint; + +template +std::ostream& operator<<(std::ostream &out, const r1cs_constraint &c); + +template +std::istream& operator>>(std::istream &in, r1cs_constraint &c); + +/** + * A R1CS constraint is a formal expression of the form + * + * < A , X > * < B , X > = < C , X > , + * + * where X = (x_0,x_1,...,x_m) is a vector of formal variables and A,B,C each + * consist of 1+m elements in . + * + * A R1CS constraint is used to construct a R1CS constraint system (see below). + */ +template +class r1cs_constraint { +public: + + linear_combination a, b, c; + + r1cs_constraint() {}; + r1cs_constraint(const linear_combination &a, + const linear_combination &b, + const linear_combination &c); + + r1cs_constraint(const std::initializer_list > &A, + const std::initializer_list > &B, + const std::initializer_list > &C); + + bool operator==(const r1cs_constraint &other) const; + + friend std::ostream& operator<< (std::ostream &out, const r1cs_constraint &c); + friend std::istream& operator>> (std::istream &in, r1cs_constraint &c); +}; + +/************************* R1CS variable assignment **************************/ + +/** + * A R1CS variable assignment is a vector of elements that represents + * a candidate solution to a R1CS constraint system (see below). + */ + +/* TODO: specify that it does *NOT* include the constant 1 */ +template +using r1cs_primary_input = std::vector; + +template +using r1cs_auxiliary_input = std::vector; + +template +using r1cs_variable_assignment = std::vector; /* note the changed name! (TODO: remove this comment after primary_input transition is complete) */ + +/************************* R1CS constraint system ****************************/ + +template +class r1cs_constraint_system; + +template +std::ostream& operator<<(std::ostream &out, const r1cs_constraint_system &cs); + +template +std::istream& operator>>(std::istream &in, r1cs_constraint_system &cs); + +/** + * A system of R1CS constraints looks like + * + * { < A_k , X > * < B_k , X > = < C_k , X > }_{k=1}^{n} . + * + * In other words, the system is satisfied if and only if there exist a + * USCS variable assignment for which each R1CS constraint is satisfied. + * + * NOTE: + * The 0-th variable (i.e., "x_{0}") always represents the constant 1. + * Thus, the 0-th variable is not included in num_variables. + */ +template +class r1cs_constraint_system { +public: + size_t primary_input_size; + size_t auxiliary_input_size; + + std::vector > constraints; + + r1cs_constraint_system() : primary_input_size(0), auxiliary_input_size(0) {} + + size_t num_inputs() const; + size_t num_variables() const; + size_t num_constraints() const; + +#ifdef DEBUG + std::map constraint_annotations; + std::map variable_annotations; +#endif + + bool is_valid() const; + bool is_satisfied(const r1cs_primary_input &primary_input, + const r1cs_auxiliary_input &auxiliary_input) const; + + void add_constraint(const r1cs_constraint &c); + void add_constraint(const r1cs_constraint &c, const std::string &annotation); + + void swap_AB_if_beneficial(); + + bool operator==(const r1cs_constraint_system &other) const; + + friend std::ostream& operator<< (std::ostream &out, const r1cs_constraint_system &cs); + friend std::istream& operator>> (std::istream &in, r1cs_constraint_system &cs); + + void report_linear_constraint_statistics() const; +}; + + +} // libsnark + +#include "relations/constraint_satisfaction_problems/r1cs/r1cs.tcc" + +#endif // R1CS_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/relations/constraint_satisfaction_problems/r1cs/r1cs.tcc b/privacy/zsl/zsl/snark/libsnark/src/relations/constraint_satisfaction_problems/r1cs/r1cs.tcc new file mode 100644 index 0000000..0faa56a --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/relations/constraint_satisfaction_problems/r1cs/r1cs.tcc @@ -0,0 +1,310 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for: + - a R1CS constraint, + - a R1CS variable assignment, and + - a R1CS constraint system. + + See r1cs.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef R1CS_TCC_ +#define R1CS_TCC_ + +#include +#include +#include +#include "common/utils.hpp" +#include "common/profiling.hpp" +#include "algebra/fields/bigint.hpp" + +namespace libsnark { + +template +r1cs_constraint::r1cs_constraint(const linear_combination &a, + const linear_combination &b, + const linear_combination &c) : + a(a), b(b), c(c) +{ +} + +template +r1cs_constraint::r1cs_constraint(const std::initializer_list > &A, + const std::initializer_list > &B, + const std::initializer_list > &C) +{ + for (auto lc_A : A) + { + a.terms.insert(a.terms.end(), lc_A.terms.begin(), lc_A.terms.end()); + } + for (auto lc_B : B) + { + b.terms.insert(b.terms.end(), lc_B.terms.begin(), lc_B.terms.end()); + } + for (auto lc_C : C) + { + c.terms.insert(c.terms.end(), lc_C.terms.begin(), lc_C.terms.end()); + } +} + +template +bool r1cs_constraint::operator==(const r1cs_constraint &other) const +{ + return (this->a == other.a && + this->b == other.b && + this->c == other.c); +} + +template +std::ostream& operator<<(std::ostream &out, const r1cs_constraint &c) +{ + out << c.a; + out << c.b; + out << c.c; + + return out; +} + +template +std::istream& operator>>(std::istream &in, r1cs_constraint &c) +{ + in >> c.a; + in >> c.b; + in >> c.c; + + return in; +} + +template +size_t r1cs_constraint_system::num_inputs() const +{ + return primary_input_size; +} + +template +size_t r1cs_constraint_system::num_variables() const +{ + return primary_input_size + auxiliary_input_size; +} + + +template +size_t r1cs_constraint_system::num_constraints() const +{ + return constraints.size(); +} + +template +bool r1cs_constraint_system::is_valid() const +{ + if (this->num_inputs() > this->num_variables()) return false; + + for (size_t c = 0; c < constraints.size(); ++c) + { + if (!(constraints[c].a.is_valid(this->num_variables()) && + constraints[c].b.is_valid(this->num_variables()) && + constraints[c].c.is_valid(this->num_variables()))) + { + return false; + } + } + + return true; +} + +template +void dump_r1cs_constraint(const r1cs_constraint &constraint, + const r1cs_variable_assignment &full_variable_assignment, + const std::map &variable_annotations) +{ + printf("terms for a:\n"); constraint.a.print_with_assignment(full_variable_assignment, variable_annotations); + printf("terms for b:\n"); constraint.b.print_with_assignment(full_variable_assignment, variable_annotations); + printf("terms for c:\n"); constraint.c.print_with_assignment(full_variable_assignment, variable_annotations); +} + +template +bool r1cs_constraint_system::is_satisfied(const r1cs_primary_input &primary_input, + const r1cs_auxiliary_input &auxiliary_input) const +{ + assert(primary_input.size() == num_inputs()); + assert(primary_input.size() + auxiliary_input.size() == num_variables()); + + r1cs_variable_assignment full_variable_assignment = primary_input; + full_variable_assignment.insert(full_variable_assignment.end(), auxiliary_input.begin(), auxiliary_input.end()); + + for (size_t c = 0; c < constraints.size(); ++c) + { + const FieldT ares = constraints[c].a.evaluate(full_variable_assignment); + const FieldT bres = constraints[c].b.evaluate(full_variable_assignment); + const FieldT cres = constraints[c].c.evaluate(full_variable_assignment); + + if (!(ares*bres == cres)) + { +#ifdef DEBUG + auto it = constraint_annotations.find(c); + printf("constraint %zu (%s) unsatisfied\n", c, (it == constraint_annotations.end() ? "no annotation" : it->second.c_str())); + printf(" = "); ares.print(); + printf(" = "); bres.print(); + printf(" = "); cres.print(); + printf("constraint was:\n"); + dump_r1cs_constraint(constraints[c], full_variable_assignment, variable_annotations); +#endif // DEBUG + return false; + } + } + + return true; +} + +template +void r1cs_constraint_system::add_constraint(const r1cs_constraint &c) +{ + constraints.emplace_back(c); +} + +template +void r1cs_constraint_system::add_constraint(const r1cs_constraint &c, const std::string &annotation) +{ +#ifdef DEBUG + constraint_annotations[constraints.size()] = annotation; +#endif + constraints.emplace_back(c); +} + +template +void r1cs_constraint_system::swap_AB_if_beneficial() +{ + enter_block("Call to r1cs_constraint_system::swap_AB_if_beneficial"); + + enter_block("Estimate densities"); + bit_vector touched_by_A(this->num_variables() + 1, false), touched_by_B(this->num_variables() + 1, false); + + for (size_t i = 0; i < this->constraints.size(); ++i) + { + for (size_t j = 0; j < this->constraints[i].a.terms.size(); ++j) + { + touched_by_A[this->constraints[i].a.terms[j].index] = true; + } + + for (size_t j = 0; j < this->constraints[i].b.terms.size(); ++j) + { + touched_by_B[this->constraints[i].b.terms[j].index] = true; + } + } + + size_t non_zero_A_count = 0, non_zero_B_count = 0; + for (size_t i = 0; i < this->num_variables() + 1; ++i) + { + non_zero_A_count += touched_by_A[i] ? 1 : 0; + non_zero_B_count += touched_by_B[i] ? 1 : 0; + } + + if (!inhibit_profiling_info) + { + print_indent(); printf("* Non-zero A-count (estimate): %zu\n", non_zero_A_count); + print_indent(); printf("* Non-zero B-count (estimate): %zu\n", non_zero_B_count); + } + leave_block("Estimate densities"); + + if (non_zero_B_count > non_zero_A_count) + { + enter_block("Perform the swap"); + for (size_t i = 0; i < this->constraints.size(); ++i) + { + std::swap(this->constraints[i].a, this->constraints[i].b); + } + leave_block("Perform the swap"); + } + else + { + print_indent(); printf("Swap is not beneficial, not performing\n"); + } + + leave_block("Call to r1cs_constraint_system::swap_AB_if_beneficial"); +} + +template +bool r1cs_constraint_system::operator==(const r1cs_constraint_system &other) const +{ + return (this->constraints == other.constraints && + this->primary_input_size == other.primary_input_size && + this->auxiliary_input_size == other.auxiliary_input_size); +} + +template +std::ostream& operator<<(std::ostream &out, const r1cs_constraint_system &cs) +{ + out << cs.primary_input_size << "\n"; + out << cs.auxiliary_input_size << "\n"; + + out << cs.num_constraints() << "\n"; + for (const r1cs_constraint& c : cs.constraints) + { + out << c; + } + + return out; +} + +template +std::istream& operator>>(std::istream &in, r1cs_constraint_system &cs) +{ + in >> cs.primary_input_size; + in >> cs.auxiliary_input_size; + + cs.constraints.clear(); + + size_t s; + in >> s; + + char b; + in.read(&b, 1); + + cs.constraints.reserve(s); + + for (size_t i = 0; i < s; ++i) + { + r1cs_constraint c; + in >> c; + cs.constraints.emplace_back(c); + } + + return in; +} + +template +void r1cs_constraint_system::report_linear_constraint_statistics() const +{ +#ifdef DEBUG + for (size_t i = 0; i < constraints.size(); ++i) + { + auto &constr = constraints[i]; + bool a_is_const = true; + for (auto &t : constr.a.terms) + { + a_is_const = a_is_const && (t.index == 0); + } + + bool b_is_const = true; + for (auto &t : constr.b.terms) + { + b_is_const = b_is_const && (t.index == 0); + } + + if (a_is_const || b_is_const) + { + auto it = constraint_annotations.find(i); + printf("%s\n", (it == constraint_annotations.end() ? FORMAT("", "constraint_%zu", i) : it->second).c_str()); + } + } +#endif +} + +} // libsnark +#endif // R1CS_TCC_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/relations/constraint_satisfaction_problems/uscs/examples/uscs_examples.hpp b/privacy/zsl/zsl/snark/libsnark/src/relations/constraint_satisfaction_problems/uscs/examples/uscs_examples.hpp new file mode 100644 index 0000000..9edebef --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/relations/constraint_satisfaction_problems/uscs/examples/uscs_examples.hpp @@ -0,0 +1,72 @@ +/** @file + + Declaration of interfaces for a USCS example, as well as functions to sample + USCS examples with prescribed parameters (according to some distribution). + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef USCS_EXAMPLES_HPP_ +#define USCS_EXAMPLES_HPP_ + +#include "relations/constraint_satisfaction_problems/uscs/uscs.hpp" + +namespace libsnark { + +/** + * A USCS example comprises a USCS constraint system, USCS input, and USCS witness. + */ +template +struct uscs_example { + uscs_constraint_system constraint_system; + uscs_primary_input primary_input; + uscs_auxiliary_input auxiliary_input; + + uscs_example() = default; + uscs_example(const uscs_example &other) = default; + uscs_example(const uscs_constraint_system &constraint_system, + const uscs_primary_input &primary_input, + const uscs_auxiliary_input &auxiliary_input) : + constraint_system(constraint_system), + primary_input(primary_input), + auxiliary_input(auxiliary_input) + {}; + uscs_example(uscs_constraint_system &&constraint_system, + uscs_primary_input &&primary_input, + uscs_auxiliary_input &&auxiliary_input) : + constraint_system(std::move(constraint_system)), + primary_input(std::move(primary_input)), + auxiliary_input(std::move(auxiliary_input)) + {}; +}; + +/** + * Generate a USCS example such that: + * - the number of constraints of the USCS constraint system is num_constraints; + * - the number of variables of the USCS constraint system is (approximately) num_constraints; + * - the number of inputs of the USCS constraint system is num_inputs; + * - the USCS input consists of ``full'' field elements (typically require the whole log|Field| bits to represent). + */ +template +uscs_example generate_uscs_example_with_field_input(const size_t num_constraints, + const size_t num_inputs); + +/** + * Generate a USCS example such that: + * - the number of constraints of the USCS constraint system is num_constraints; + * - the number of variables of the USCS constraint system is (approximately) num_constraints; + * - the number of inputs of the USCS constraint system is num_inputs; + * - the USCS input consists of binary values (as opposed to ``full'' field elements). + */ +template +uscs_example generate_uscs_example_with_binary_input(const size_t num_constraints, + const size_t num_inputs); + +} // libsnark + +#include "relations/constraint_satisfaction_problems/uscs/examples/uscs_examples.tcc" + +#endif // USCS_EXAMPLES_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/relations/constraint_satisfaction_problems/uscs/examples/uscs_examples.tcc b/privacy/zsl/zsl/snark/libsnark/src/relations/constraint_satisfaction_problems/uscs/examples/uscs_examples.tcc new file mode 100644 index 0000000..90f011f --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/relations/constraint_satisfaction_problems/uscs/examples/uscs_examples.tcc @@ -0,0 +1,137 @@ +/** @file + ***************************************************************************** + + Implementation of functions to sample USCS examples with prescribed parameters + (according to some distribution). + + See uscs_examples.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef USCS_EXAMPLES_TCC_ +#define USCS_EXAMPLES_TCC_ + +#include + +#include "common/utils.hpp" + +namespace libsnark { + +template +uscs_example generate_uscs_example_with_field_input(const size_t num_constraints, + const size_t num_inputs) +{ + enter_block("Call to generate_uscs_example_with_field_input"); + + assert(num_inputs >= 1); + assert(num_constraints >= num_inputs); + + uscs_constraint_system cs; + cs.primary_input_size = num_inputs; + cs.auxiliary_input_size = num_constraints - num_inputs; + + uscs_variable_assignment full_variable_assignment; + for (size_t i = 0; i < num_constraints; ++i) + { + full_variable_assignment.emplace_back(FieldT(std::rand())); + } + + for (size_t i = 0; i < num_constraints; ++i) + { + size_t x, y, z; + + do + { + x = std::rand() % num_constraints; + y = std::rand() % num_constraints; + z = std::rand() % num_constraints; + } while (x == z || y == z); + + const FieldT x_coeff = FieldT(std::rand()); + const FieldT y_coeff = FieldT(std::rand()); + const FieldT val = (std::rand() % 2 == 0 ? FieldT::one() : -FieldT::one()); + const FieldT z_coeff = (val - x_coeff * full_variable_assignment[x] - y_coeff * full_variable_assignment[y]) * full_variable_assignment[z].inverse(); + + uscs_constraint constr; + constr.add_term(x+1, x_coeff); + constr.add_term(y+1, y_coeff); + constr.add_term(z+1, z_coeff); + + cs.add_constraint(constr); + } + + /* split variable assignment */ + uscs_primary_input primary_input(full_variable_assignment.begin(), full_variable_assignment.begin() + num_inputs); + uscs_primary_input auxiliary_input(full_variable_assignment.begin() + num_inputs, full_variable_assignment.end()); + + /* sanity checks */ + assert(cs.num_variables() == full_variable_assignment.size()); + assert(cs.num_variables() >= num_inputs); + assert(cs.num_inputs() == num_inputs); + assert(cs.num_constraints() == num_constraints); + assert(cs.is_satisfied(primary_input, auxiliary_input)); + + leave_block("Call to generate_uscs_example_with_field_input"); + + return uscs_example(std::move(cs), std::move(primary_input), std::move(auxiliary_input)); +} + +template +uscs_example generate_uscs_example_with_binary_input(const size_t num_constraints, + const size_t num_inputs) +{ + enter_block("Call to generate_uscs_example_with_binary_input"); + + assert(num_inputs >= 1); + + uscs_constraint_system cs; + cs.primary_input_size = num_inputs; + cs.auxiliary_input_size = num_constraints; + + uscs_variable_assignment full_variable_assignment; + for (size_t i = 0; i < num_inputs; ++i) + { + full_variable_assignment.push_back(FieldT(std::rand() % 2)); + } + + size_t lastvar = num_inputs-1; + for (size_t i = 0; i < num_constraints; ++i) + { + ++lastvar; + + /* chose two random bits and XOR them together */ + const size_t u = (i == 0 ? std::rand() % num_inputs : std::rand() % i); + const size_t v = (i == 0 ? std::rand() % num_inputs : std::rand() % i); + + uscs_constraint constr; + constr.add_term(u+1, 1); + constr.add_term(v+1, 1); + constr.add_term(lastvar+1, 1); + constr.add_term(0,-FieldT::one()); // shift constant term (which is 0) by 1 + + cs.add_constraint(constr); + full_variable_assignment.push_back(full_variable_assignment[u] + full_variable_assignment[v] - full_variable_assignment[u] * full_variable_assignment[v] - full_variable_assignment[u] * full_variable_assignment[v]); + } + + /* split variable assignment */ + uscs_primary_input primary_input(full_variable_assignment.begin(), full_variable_assignment.begin() + num_inputs); + uscs_primary_input auxiliary_input(full_variable_assignment.begin() + num_inputs, full_variable_assignment.end()); + + /* sanity checks */ + assert(cs.num_variables() == full_variable_assignment.size()); + assert(cs.num_variables() >= num_inputs); + assert(cs.num_inputs() == num_inputs); + assert(cs.num_constraints() == num_constraints); + assert(cs.is_satisfied(primary_input, auxiliary_input)); + + leave_block("Call to generate_uscs_example_with_binary_input"); + + return uscs_example(std::move(cs), std::move(primary_input), std::move(auxiliary_input)); +} + +} // libsnark +#endif // USCS_EXAMPLES_TCC diff --git a/privacy/zsl/zsl/snark/libsnark/src/relations/constraint_satisfaction_problems/uscs/uscs.hpp b/privacy/zsl/zsl/snark/libsnark/src/relations/constraint_satisfaction_problems/uscs/uscs.hpp new file mode 100644 index 0000000..9a189e0 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/relations/constraint_satisfaction_problems/uscs/uscs.hpp @@ -0,0 +1,124 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for: + - a USCS constraint, + - a USCS variable assignment, and + - a USCS constraint system. + + Above, USCS stands for "Unitary-Square Constraint System". + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef USCS_HPP_ +#define USCS_HPP_ + +#include +#include +#include +#include +#include + +#include "relations/variable.hpp" + +namespace libsnark { + +/************************* USCS constraint ***********************************/ + +/** + * A USCS constraint is a formal expression of the form + * + * \sum_{i=1}^{m} a_i * x_{i} , + * + * where each a_i is in and each x_{i} is a formal variable. + * + * A USCS constraint is used to construct a USCS constraint system (see below). + */ +template +using uscs_constraint = linear_combination; + + +/************************* USCS variable assignment **************************/ + +/** + * A USCS variable assignment is a vector of elements that represents + * a candidate solution to a USCS constraint system (see below). + */ +template +using uscs_primary_input = std::vector; + +template +using uscs_auxiliary_input = std::vector; + +template +using uscs_variable_assignment = std::vector; + + + +/************************* USCS constraint system ****************************/ + +template +class uscs_constraint_system; + +template +std::ostream& operator<<(std::ostream &out, const uscs_constraint_system &cs); + +template +std::istream& operator>>(std::istream &in, uscs_constraint_system &cs); + +/** + * A system of USCS constraints looks like + * + * { ( \sum_{i=1}^{m_k} a_{k,i} * x_{k,i} )^2 = 1 }_{k=1}^{n} . + * + * In other words, the system is satisfied if and only if there exist a + * USCS variable assignment for which each USCS constraint evaluates to -1 or 1. + * + * NOTE: + * The 0-th variable (i.e., "x_{0}") always represents the constant 1. + * Thus, the 0-th variable is not included in num_variables. + */ +template +class uscs_constraint_system { +public: + size_t primary_input_size; + size_t auxiliary_input_size; + + std::vector > constraints; + + uscs_constraint_system() : primary_input_size(0), auxiliary_input_size(0) {}; + + size_t num_inputs() const; + size_t num_variables() const; + size_t num_constraints() const; + +#ifdef DEBUG + std::map constraint_annotations; + std::map variable_annotations; +#endif + + bool is_valid() const; + bool is_satisfied(const uscs_primary_input &primary_input, + const uscs_auxiliary_input &auxiliary_input) const; + + void add_constraint(const uscs_constraint &constraint); + void add_constraint(const uscs_constraint &constraint, const std::string &annotation); + + bool operator==(const uscs_constraint_system &other) const; + + friend std::ostream& operator<< (std::ostream &out, const uscs_constraint_system &cs); + friend std::istream& operator>> (std::istream &in, uscs_constraint_system &cs); + + void report_linear_constraint_statistics() const; +}; + + +} // libsnark + +#include "relations/constraint_satisfaction_problems/uscs/uscs.tcc" + +#endif // USCS_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/relations/constraint_satisfaction_problems/uscs/uscs.tcc b/privacy/zsl/zsl/snark/libsnark/src/relations/constraint_satisfaction_problems/uscs/uscs.tcc new file mode 100644 index 0000000..e7a8324 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/relations/constraint_satisfaction_problems/uscs/uscs.tcc @@ -0,0 +1,192 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for: + - a USCS constraint, + - a USCS variable assignment, and + - a USCS constraint system. + + See uscs.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef USCS_TCC_ +#define USCS_TCC_ + +#include +#include +#include +#include "common/utils.hpp" +#include "common/profiling.hpp" +#include "algebra/fields/bigint.hpp" + +namespace libsnark { + +template +size_t uscs_constraint_system::num_inputs() const +{ + return primary_input_size; +} + +template +size_t uscs_constraint_system::num_variables() const +{ + return primary_input_size + auxiliary_input_size; +} + + +template +size_t uscs_constraint_system::num_constraints() const +{ + return constraints.size(); +} + +template +bool uscs_constraint_system::is_valid() const +{ + if (this->num_inputs() > this->num_variables()) return false; + + for (size_t c = 0; c < constraints.size(); ++c) + { + if (!valid_vector(constraints[c], this->num_variables())) + { + return false; + } + } + + return true; +} + +template +void dump_uscs_constraint(const uscs_constraint &constraint, + const uscs_variable_assignment &full_variable_assignment, + const std::map &variable_annotations) +{ + printf("terms:\n"); + constraint.print_with_assignment(full_variable_assignment, variable_annotations); +} + +template +bool uscs_constraint_system::is_satisfied(const uscs_primary_input &primary_input, + const uscs_auxiliary_input &auxiliary_input) const +{ + assert(primary_input.size() == num_inputs()); + assert(primary_input.size() + auxiliary_input.size() == num_variables()); + + uscs_variable_assignment full_variable_assignment = primary_input; + full_variable_assignment.insert(full_variable_assignment.end(), auxiliary_input.begin(), auxiliary_input.end()); + + for (size_t c = 0; c < constraints.size(); ++c) + { + FieldT res = constraints[c].evaluate(full_variable_assignment); + if (!(res.squared() == FieldT::one())) + { +#ifdef DEBUG + auto it = constraint_annotations.find(c); + printf("constraint %zu (%s) unsatisfied\n", c, (it == constraint_annotations.end() ? "no annotation" : it->second.c_str())); + printf(" = "); res.print(); + printf("constraint was:\n"); + dump_uscs_constraint(constraints[c], full_variable_assignment, variable_annotations); +#endif // DEBUG + return false; + } + } + + return true; +} + +template +void uscs_constraint_system::add_constraint(const uscs_constraint &c) +{ + constraints.emplace_back(c); +} + +template +void uscs_constraint_system::add_constraint(const uscs_constraint &c, const std::string &annotation) +{ +#ifdef DEBUG + constraint_annotations[constraints.size()] = annotation; +#else + UNUSED(annotation); +#endif + constraints.emplace_back(c); +} + +template +bool uscs_constraint_system::operator==(const uscs_constraint_system &other) const +{ + return (this->constraints == other.constraints && + this->primary_input_size == other.primary_input_size && + this->auxiliary_input_size == other.auxiliary_input_size); +} + +template +std::ostream& operator<<(std::ostream &out, const uscs_constraint_system &cs) +{ + out << cs.primary_input_size << "\n"; + out << cs.auxiliary_input_size << "\n"; + + out << cs.num_constraints() << "\n"; + for (const uscs_constraint& c : cs.constraints) + { + out << c; + } + + return out; +} + +template +std::istream& operator>>(std::istream &in, uscs_constraint_system &cs) +{ + in >> cs.primary_input_size; + in >> cs.auxiliary_input_size; + + cs.constraints.clear(); + + size_t s; + in >> s; + + char b; + in.read(&b, 1); + + cs.constraints.reserve(s); + + for (size_t i = 0; i < s; ++i) + { + uscs_constraint c; + in >> c; + cs.constraints.emplace_back(c); + } + + return in; +} + +template +void uscs_constraint_system::report_linear_constraint_statistics() const +{ +#ifdef DEBUG + for (size_t i = 0; i < constraints.size(); ++i) + { + auto &constr = constraints[i]; + bool a_is_const = true; + for (auto &t : constr.terms) + { + a_is_const = a_is_const && (t.index == 0); + } + + if (a_is_const) + { + auto it = constraint_annotations.find(i); + printf("%s\n", (it == constraint_annotations.end() ? FORMAT("", "constraint_%zu", i) : it->second).c_str()); + } + } +#endif +} + +} // libsnark + +#endif // USCS_TCC_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/relations/ram_computations/memory/delegated_ra_memory.hpp b/privacy/zsl/zsl/snark/libsnark/src/relations/ram_computations/memory/delegated_ra_memory.hpp new file mode 100644 index 0000000..0a17c3a --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/relations/ram_computations/memory/delegated_ra_memory.hpp @@ -0,0 +1,50 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for a delegated random-access memory. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef DELEGATED_RA_MEMORY_HPP_ +#define DELEGATED_RA_MEMORY_HPP_ + +#include +#include +#include + +#include "common/data_structures/merkle_tree.hpp" +#include "relations/ram_computations/memory/memory_interface.hpp" + +namespace libsnark { + +template +class delegated_ra_memory : public memory_interface { +private: + bit_vector int_to_tree_elem(const size_t i) const; + size_t int_from_tree_elem(const bit_vector &v) const; + + std::unique_ptr > contents; + +public: + delegated_ra_memory(const size_t num_addresses, const size_t value_size); + delegated_ra_memory(const size_t num_addresses, const size_t value_size, const std::vector &contents_as_vector); + delegated_ra_memory(const size_t num_addresses, const size_t value_size, const memory_contents &contents_as_map); + + size_t get_value(const size_t address) const; + void set_value(const size_t address, const size_t value); + + typename HashT::hash_value_type get_root() const; + typename HashT::merkle_authentication_path_type get_path(const size_t address) const; + + void dump() const; +}; + +} // libsnark + +#include "relations/ram_computations/memory/delegated_ra_memory.tcc" + +#endif // DELEGATED_RA_MEMORY_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/relations/ram_computations/memory/delegated_ra_memory.tcc b/privacy/zsl/zsl/snark/libsnark/src/relations/ram_computations/memory/delegated_ra_memory.tcc new file mode 100644 index 0000000..b29b284 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/relations/ram_computations/memory/delegated_ra_memory.tcc @@ -0,0 +1,114 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for a delegated random-access memory. + + See delegated_ra_memory.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef DELEGATED_RA_MEMORY_TCC +#define DELEGATED_RA_MEMORY_TCC + +#include + +#include "common/profiling.hpp" +#include "common/utils.hpp" + +namespace libsnark { + +template +bit_vector delegated_ra_memory::int_to_tree_elem(const size_t i) const +{ + bit_vector v(value_size, false); + for (size_t k = 0; k < value_size; ++k) + { + v[k] = ((i & (1ul << k)) != 0); + } + return v; +} + +template +size_t delegated_ra_memory::int_from_tree_elem(const bit_vector &v) const +{ + size_t result = 0; + for (size_t i = 0; i < value_size; ++i) + { + result |= (v[i] ? 1ul : 0ul) << i; + } + + return result; +} + +template +delegated_ra_memory::delegated_ra_memory(const size_t num_addresses, + const size_t value_size) : + memory_interface(num_addresses, value_size) +{ + contents.reset(new merkle_tree(log2(num_addresses), value_size)); +} + +template +delegated_ra_memory::delegated_ra_memory(const size_t num_addresses, + const size_t value_size, + const std::vector &contents_as_vector) : + memory_interface(num_addresses, value_size) +{ + std::vector contents_as_bit_vector_vector(contents.size()); + std::transform(contents_as_vector.begin(), contents_as_vector.end(), contents_as_bit_vector_vector, [this](size_t value) { return int_to_tree_elem(value); }); + contents.reset(new merkle_tree(log2(num_addresses), value_size, contents_as_bit_vector_vector)); +} + +template +delegated_ra_memory::delegated_ra_memory(const size_t num_addresses, + const size_t value_size, + const std::map &contents_as_map) : + memory_interface(num_addresses, value_size) +{ + std::map contents_as_bit_vector_map; + for (auto &it : contents_as_map) + { + contents_as_bit_vector_map[it.first] = int_to_tree_elem(it.second); + } + + contents.reset(new merkle_tree(log2(num_addresses), value_size, contents_as_bit_vector_map)); +} + +template +size_t delegated_ra_memory::get_value(const size_t address) const +{ + return int_from_tree_elem(contents->get_value(address)); +} + +template +void delegated_ra_memory::set_value(const size_t address, + const size_t value) +{ + contents->set_value(address, int_to_tree_elem(value)); +} + +template +typename HashT::hash_value_type delegated_ra_memory::get_root() const +{ + return contents->get_root(); +} + +template +typename HashT::merkle_authentication_path_type delegated_ra_memory::get_path(const size_t address) const +{ + return contents->get_path(address); +} + +template +void delegated_ra_memory::dump() const +{ + contents->dump(); +} + +} // libsnark + +#endif // DELEGATED_RA_MEMORY_TCC diff --git a/privacy/zsl/zsl/snark/libsnark/src/relations/ram_computations/memory/examples/memory_contents_examples.cpp b/privacy/zsl/zsl/snark/libsnark/src/relations/ram_computations/memory/examples/memory_contents_examples.cpp new file mode 100644 index 0000000..336958e --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/relations/ram_computations/memory/examples/memory_contents_examples.cpp @@ -0,0 +1,67 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for functions to sample examples of memory contents. + + See memory_contents_examples.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include "relations/ram_computations/memory/examples/memory_contents_examples.hpp" + +#include +#include +#include + +namespace libsnark { + +memory_contents block_memory_contents(const size_t num_addresses, + const size_t value_size, + const size_t block1_size, + const size_t block2_size) +{ + const size_t max_unit = 1ul< unfilled; + for (size_t i = 0; i < num_addresses; ++i) + { + unfilled.insert(i); + } + + memory_contents result; + for (size_t i = 0; i < num_filled; ++i) + { + auto it = unfilled.begin(); + std::advance(it, std::rand() % unfilled.size()); + result[*it] = std::rand() % max_unit; + unfilled.erase(it); + } + + return result; +} + +} // libsnark diff --git a/privacy/zsl/zsl/snark/libsnark/src/relations/ram_computations/memory/examples/memory_contents_examples.hpp b/privacy/zsl/zsl/snark/libsnark/src/relations/ram_computations/memory/examples/memory_contents_examples.hpp new file mode 100644 index 0000000..6fbffea --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/relations/ram_computations/memory/examples/memory_contents_examples.hpp @@ -0,0 +1,39 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for functions to sample examples of memory contents. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef MEMORY_CONTENTS_EXAMPLES_HPP_ +#define MEMORY_CONTENTS_EXAMPLES_HPP_ + +#include "relations/ram_computations/memory/memory_interface.hpp" + +namespace libsnark { + +/** + * Sample memory contents consisting of two blocks of random values; + * the first block is located at the beginning of memory, while + * the second block is located half-way through memory. + */ +memory_contents block_memory_contents(const size_t num_addresses, + const size_t value_size, + const size_t block1_size, + const size_t block2_size); + +/** + * Sample memory contents having a given number of non-zero entries; + * each non-zero entry is a random value at a random address (approximately). + */ +memory_contents random_memory_contents(const size_t num_addresses, + const size_t value_size, + const size_t num_filled); + +} // libsnark + +#endif // MEMORY_CONTENTS_EXAMPLES_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/relations/ram_computations/memory/memory_interface.hpp b/privacy/zsl/zsl/snark/libsnark/src/relations/ram_computations/memory/memory_interface.hpp new file mode 100644 index 0000000..b20281a --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/relations/ram_computations/memory/memory_interface.hpp @@ -0,0 +1,54 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for a memory interface. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef MEMORY_INTERFACE_HPP_ +#define MEMORY_INTERFACE_HPP_ + +#include +#include +#include + +namespace libsnark { + +/** + * A function from addresses to values that represents a memory's contents. + */ +typedef std::map memory_contents; + +/** + * A memory interface is a virtual class for specifying and maintining a memory. + * + * A memory is parameterized by two quantities: + * - num_addresses (which specifies the number of addresses); and + * - value_size (which specifies the number of bits stored at each address). + * + * The methods get_val and set_val can be used to load and store values. + */ +class memory_interface { +public: + + size_t num_addresses; + size_t value_size; + + memory_interface(const size_t num_addresses, const size_t value_size) : + num_addresses(num_addresses), + value_size(value_size) + {} + memory_interface(const size_t num_addresses, const size_t value_size, const std::vector &contents_as_vector); + memory_interface(const size_t num_addresses, const size_t value_size, const memory_contents &contents); + + virtual size_t get_value(const size_t address) const = 0; + virtual void set_value(const size_t address, const size_t value) = 0; +}; + +} // libsnark + +#endif // MEMORY_INTERFACE_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/relations/ram_computations/memory/memory_store_trace.cpp b/privacy/zsl/zsl/snark/libsnark/src/relations/ram_computations/memory/memory_store_trace.cpp new file mode 100644 index 0000000..e115962 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/relations/ram_computations/memory/memory_store_trace.cpp @@ -0,0 +1,50 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for a memory store trace. + + See memory_store_trace.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include "relations/ram_computations/memory/memory_store_trace.hpp" + +namespace libsnark { + +memory_store_trace::memory_store_trace() +{ +} + +address_and_value memory_store_trace::get_trace_entry(const size_t timestamp) const +{ + auto it = entries.find(timestamp); + return (it != entries.end() ? it->second : std::make_pair(0, 0)); +} + +std::map memory_store_trace::get_all_trace_entries() const +{ + return entries; +} + +void memory_store_trace::set_trace_entry(const size_t timestamp, const address_and_value &av) +{ + entries[timestamp] = av; +} + +memory_contents memory_store_trace::as_memory_contents() const +{ + memory_contents result; + + for (auto &ts_and_addrval : entries) + { + result[ts_and_addrval.second.first] = ts_and_addrval.second.second; + } + + return result; +} + +} // libsnark diff --git a/privacy/zsl/zsl/snark/libsnark/src/relations/ram_computations/memory/memory_store_trace.hpp b/privacy/zsl/zsl/snark/libsnark/src/relations/ram_computations/memory/memory_store_trace.hpp new file mode 100644 index 0000000..dd88f35 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/relations/ram_computations/memory/memory_store_trace.hpp @@ -0,0 +1,43 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for a memory store trace. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef MEMORY_STORE_TRACE_HPP_ +#define MEMORY_STORE_TRACE_HPP_ + +#include "relations/ram_computations/memory/memory_interface.hpp" + +namespace libsnark { + +/** + * A pair consisting of an address and a value. + * It represents a memory store. + */ +typedef std::pair address_and_value; + +/** + * A list in which each component consists of a timestamp and a memory store. + */ +class memory_store_trace { +private: + std::map entries; + +public: + memory_store_trace(); + address_and_value get_trace_entry(const size_t timestamp) const; + std::map get_all_trace_entries() const; + void set_trace_entry(const size_t timestamp, const address_and_value &av); + + memory_contents as_memory_contents() const; +}; + +} // libsnark + +#endif // MEMORY_STORE_TRACE_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/relations/ram_computations/memory/ra_memory.cpp b/privacy/zsl/zsl/snark/libsnark/src/relations/ram_computations/memory/ra_memory.cpp new file mode 100644 index 0000000..d16ddcd --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/relations/ram_computations/memory/ra_memory.cpp @@ -0,0 +1,57 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for a random-access memory. + + See ra_memory.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include + +#include "relations/ram_computations/memory/ra_memory.hpp" + +namespace libsnark { + +ra_memory::ra_memory(const size_t num_addresses, const size_t value_size) : + memory_interface(num_addresses, value_size) +{ +} + +ra_memory::ra_memory(const size_t num_addresses, + const size_t value_size, + const std::vector &contents_as_vector) : + memory_interface(num_addresses, value_size) +{ + /* copy std::vector into std::map */ + for (size_t i = 0; i < contents_as_vector.size(); ++i) + { + contents[i] = contents_as_vector[i]; + } +} + + +ra_memory::ra_memory(const size_t num_addresses, + const size_t value_size, + const memory_contents &contents) : + memory_interface(num_addresses, value_size), contents(contents) +{ +} + +size_t ra_memory::get_value(const size_t address) const +{ + assert(address < num_addresses); + auto it = contents.find(address); + return (it == contents.end() ? 0 : it->second); +} + +void ra_memory::set_value(const size_t address, const size_t value) +{ + contents[address] = value; +} + +} // libsnark diff --git a/privacy/zsl/zsl/snark/libsnark/src/relations/ram_computations/memory/ra_memory.hpp b/privacy/zsl/zsl/snark/libsnark/src/relations/ram_computations/memory/ra_memory.hpp new file mode 100644 index 0000000..21abd6e --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/relations/ram_computations/memory/ra_memory.hpp @@ -0,0 +1,38 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for a random-access memory. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef RA_MEMORY_HPP_ +#define RA_MEMORY_HPP_ + +#include "relations/ram_computations/memory/memory_interface.hpp" + +namespace libsnark { + +/** + * A random-access memory maintains the memory's contents via a map (from addresses to values). + */ +class ra_memory : public memory_interface { +public: + + memory_contents contents; + + ra_memory(const size_t num_addresses, const size_t value_size); + ra_memory(const size_t num_addresses, const size_t value_size, const std::vector &contents_as_vector); + ra_memory(const size_t num_addresses, const size_t value_size, const memory_contents &contents); + + size_t get_value(const size_t address) const; + void set_value(const size_t address, const size_t value); + +}; + +} // libsnark + +#endif // RA_MEMORY_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/relations/ram_computations/rams/examples/ram_examples.hpp b/privacy/zsl/zsl/snark/libsnark/src/relations/ram_computations/rams/examples/ram_examples.hpp new file mode 100644 index 0000000..93c9bf6 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/relations/ram_computations/rams/examples/ram_examples.hpp @@ -0,0 +1,45 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for a RAM example, as well as functions to sample + RAM examples with prescribed parameters (according to some distribution). + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef RAM_EXAMPLES_HPP_ +#define RAM_EXAMPLES_HPP_ + +#include "relations/ram_computations/rams/ram_params.hpp" + +namespace libsnark { + +template +struct ram_example { + ram_architecture_params ap; + size_t boot_trace_size_bound; + size_t time_bound; + ram_boot_trace boot_trace; + ram_input_tape auxiliary_input; +}; + +/** + * For now: only specialized to TinyRAM + */ +template +ram_example gen_ram_example_simple(const ram_architecture_params &ap, const size_t boot_trace_size_bound, const size_t time_bound, const bool satisfiable=true); + +/** + * For now: only specialized to TinyRAM + */ +template +ram_example gen_ram_example_complex(const ram_architecture_params &ap, const size_t boot_trace_size_bound, const size_t time_bound, const bool satisfiable=true); + +} // libsnark + +#include "relations/ram_computations/rams/examples/ram_examples.tcc" + +#endif // RAM_EXAMPLES_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/relations/ram_computations/rams/examples/ram_examples.tcc b/privacy/zsl/zsl/snark/libsnark/src/relations/ram_computations/rams/examples/ram_examples.tcc new file mode 100644 index 0000000..c58c248 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/relations/ram_computations/rams/examples/ram_examples.tcc @@ -0,0 +1,121 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for a RAM example, as well as functions to sample + RAM examples with prescribed parameters (according to some distribution). + + See ram_examples.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef RAM_EXAMPLES_TCC_ +#define RAM_EXAMPLES_TCC_ + +#include "relations/ram_computations/rams/tinyram/tinyram_aux.hpp" + +namespace libsnark { + +template +ram_example gen_ram_example_simple(const ram_architecture_params &ap, const size_t boot_trace_size_bound, const size_t time_bound, const bool satisfiable) +{ + enter_block("Call to gen_ram_example_simple"); + + const size_t program_size = boot_trace_size_bound / 2; + const size_t input_size = boot_trace_size_bound - program_size; + + ram_example result; + + result.ap = ap; + result.boot_trace_size_bound = boot_trace_size_bound; + result.time_bound = time_bound; + + tinyram_program prelude; prelude.instructions = generate_tinyram_prelude(ap); + + size_t boot_pos = 0; + for (size_t i = 0; i < prelude.instructions.size(); ++i) + { + result.boot_trace.set_trace_entry(boot_pos++, std::make_pair(i, prelude.instructions[i].as_dword(ap))); + } + + result.boot_trace[boot_pos] = std::make_pair(boot_pos++, tinyram_instruction(tinyram_opcode_ANSWER, true, 0, 0, satisfiable ? 0 : 1).as_dword(ap)); /* answer 0/1 depending on satisfiability */ + + while (boot_pos < program_size) + { + result.boot_trace.set_trace_entry(boot_pos++, random_tinyram_instruction(ap).as_dword(ap)); + } + + for (size_t i = 0; i < input_size; ++i) + { + result.boot_trace.set_trace_entry(boot_pos++, std::make_pair((1ul<<(ap.dwaddr_len()-1)) + i, std::rand() % (1ul<<(2*ap.w)))); + } + + assert(boot_pos == boot_trace_size_bound); + + leave_block("Call to gen_ram_example_simple"); + return result; +} + +template +ram_example gen_ram_example_complex(const ram_architecture_params &ap, const size_t boot_trace_size_bound, const size_t time_bound, const bool satisfiable) +{ + enter_block("Call to gen_ram_example_complex"); + + const size_t program_size = boot_trace_size_bound / 2; + const size_t input_size = boot_trace_size_bound - program_size; + + assert(2*ap.w/8*program_size < 1ul<<(ap.w-1)); + assert(ap.w/8*input_size < 1ul<<(ap.w-1)); + + ram_example result; + + result.ap = ap; + result.boot_trace_size_bound = boot_trace_size_bound; + result.time_bound = time_bound; + + tinyram_program prelude; prelude.instructions = generate_tinyram_prelude(ap); + + size_t boot_pos = 0; + for (size_t i = 0; i < prelude.instructions.size(); ++i) + { + result.boot_trace.set_trace_entry(boot_pos++, std::make_pair(i, prelude.instructions[i].as_dword(ap))); + } + + const size_t prelude_len = prelude.instructions.size(); + const size_t instr_addr = (prelude_len+4)*(2*ap.w/8); + const size_t input_addr = (1ul<<(ap.w-1)) + (ap.w/8); // byte address of the first input word + + result.boot_trace.set_trace_entry(boot_pos, std::make_pair(boot_pos, tinyram_instruction(tinyram_opcode_LOADB, true, 1, 0, instr_addr).as_dword(ap))); + ++boot_pos; + result.boot_trace.set_trace_entry(boot_pos, std::make_pair(boot_pos, tinyram_instruction(tinyram_opcode_LOADW, true, 2, 0, input_addr).as_dword(ap))); + ++boot_pos; + result.boot_trace.set_trace_entry(boot_pos, std::make_pair(boot_pos, tinyram_instruction(tinyram_opcode_SUB, false, 1, 1, 2).as_dword(ap))); + ++boot_pos; + result.boot_trace.set_trace_entry(boot_pos, std::make_pair(boot_pos, tinyram_instruction(tinyram_opcode_STOREB, true, 1, 0, instr_addr).as_dword(ap))); + ++boot_pos; + result.boot_trace.set_trace_entry(boot_pos, std::make_pair(boot_pos, tinyram_instruction(tinyram_opcode_ANSWER, true, 0, 0, 1).as_dword(ap))); + ++boot_pos; + + while (boot_pos < program_size) + { + result.boot_trace.set_trace_entry(boot_pos, std::make_pair(boot_pos, random_tinyram_instruction(ap).as_dword(ap))); + ++boot_pos; + } + + result.boot_trace.set_trace_entry(boot_pos++, std::make_pair(1ul<<(ap.dwaddr_len()-1), satisfiable ? 1ul<w == other.w); +} + +std::ostream& operator<<(std::ostream &out, const fooram_architecture_params &ap) +{ + out << ap.w << "\n"; + return out; +} + +std::istream& operator>>(std::istream &in, fooram_architecture_params &ap) +{ + in >> ap.w; + consume_newline(in); + return in; +} + +} // libsnark + diff --git a/privacy/zsl/zsl/snark/libsnark/src/relations/ram_computations/rams/fooram/fooram_aux.hpp b/privacy/zsl/zsl/snark/libsnark/src/relations/ram_computations/rams/fooram/fooram_aux.hpp new file mode 100644 index 0000000..8e16436 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/relations/ram_computations/rams/fooram/fooram_aux.hpp @@ -0,0 +1,51 @@ +/** @file + ***************************************************************************** + + Declaration of auxiliary functions for FOORAM. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef FOORAM_AUX_HPP_ +#define FOORAM_AUX_HPP_ + +#include +#include + +#include "common/utils.hpp" +#include "relations/ram_computations/memory/memory_interface.hpp" + +namespace libsnark { + +typedef std::vector fooram_program; +typedef std::vector fooram_input_tape; +typedef typename std::vector::const_iterator fooram_input_tape_iterator; + +class fooram_architecture_params { +public: + size_t w; + fooram_architecture_params(const size_t w=16); + + size_t num_addresses() const; + size_t address_size() const; + size_t value_size() const; + size_t cpu_state_size() const; + size_t initial_pc_addr() const; + + memory_contents initial_memory_contents(const fooram_program &program, + const fooram_input_tape &primary_input) const; + + bit_vector initial_cpu_state() const; + void print() const; + bool operator==(const fooram_architecture_params &other) const; + + friend std::ostream& operator<<(std::ostream &out, const fooram_architecture_params &ap); + friend std::istream& operator>>(std::istream &in, fooram_architecture_params &ap); +}; + +} // libsnark + +#endif // FOORAM_AUX_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/relations/ram_computations/rams/fooram/fooram_params.hpp b/privacy/zsl/zsl/snark/libsnark/src/relations/ram_computations/rams/fooram/fooram_params.hpp new file mode 100644 index 0000000..3a50501 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/relations/ram_computations/rams/fooram/fooram_params.hpp @@ -0,0 +1,38 @@ +/** @file + ***************************************************************************** + + Declaration of public parameters for FOORAM. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef FOORAM_PARAMS_HPP_ +#define FOORAM_PARAMS_HPP_ + +#include "gadgetlib1/gadgets/cpu_checkers/fooram/fooram_cpu_checker.hpp" +#include "relations/ram_computations/rams/fooram/fooram_aux.hpp" +#include "relations/ram_computations/rams/ram_params.hpp" + +namespace libsnark { + +template +class ram_fooram { +public: + typedef FieldT base_field_type; + typedef fooram_protoboard protoboard_type; + typedef fooram_gadget gadget_base_type; + typedef fooram_cpu_checker cpu_checker_type; + typedef fooram_architecture_params architecture_params_type; + + static size_t timestamp_length; +}; + +template +size_t ram_fooram::timestamp_length = 300; + +} // libsnark + +#endif // FOORAM_PARAMS_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/relations/ram_computations/rams/ram_params.hpp b/privacy/zsl/zsl/snark/libsnark/src/relations/ram_computations/rams/ram_params.hpp new file mode 100644 index 0000000..18a342b --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/relations/ram_computations/rams/ram_params.hpp @@ -0,0 +1,79 @@ +/** @file + ***************************************************************************** + + Declaration of public-parameter selector for RAMs. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef RAM_PARAMS_HPP_ +#define RAM_PARAMS_HPP_ + +#include + +#include "relations/ram_computations/memory/memory_store_trace.hpp" + +namespace libsnark { + +/* + When declaring a new ramT one should do a make it a class that declares typedefs for: + + base_field_type + ram_cpu_checker_type + architecture_params_type + + For ram_to_r1cs reduction currently the following are also necessary: + protoboard_type (e.g. tinyram_protoboard) + gadget_base_type (e.g. tinyram_gadget) + cpu_state_variable_type (must have pb_variable_array all_vars) + + The ramT class must also have a static size_t variable + timestamp_length, which specifies the zk-SNARK reduction timestamp + length. +*/ + +template +using ram_base_field = typename ramT::base_field_type; + +template +using ram_cpu_state = bit_vector; + +template +using ram_boot_trace = memory_store_trace; + +template +using ram_protoboard = typename ramT::protoboard_type; + +template +using ram_gadget_base = typename ramT::gadget_base_type; + +template +using ram_cpu_checker = typename ramT::cpu_checker_type; + +template +using ram_architecture_params = typename ramT::architecture_params_type; + +template +using ram_input_tape = std::vector; + +/* + One should also make the following methods for ram_architecture_params + + (We are not yet making a ram_architecture_params base class, as it + would require base class for ram_program + + TODO: make this base class) + + size_t address_size(); + size_t value_size(); + size_t cpu_state_size(); + size_t initial_pc_addr(); + bit_vector initial_cpu_state(); +*/ + +} // libsnark + +#endif // RAM_PARAMS_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/relations/ram_computations/rams/tinyram/tinyram_aux.cpp b/privacy/zsl/zsl/snark/libsnark/src/relations/ram_computations/rams/tinyram/tinyram_aux.cpp new file mode 100644 index 0000000..a205443 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/relations/ram_computations/rams/tinyram/tinyram_aux.cpp @@ -0,0 +1,371 @@ +/** @file + ***************************************************************************** + + Implementation of auxiliary functions for TinyRAM. + + See tinyram_aux.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include +#include +#include + +#include "common/profiling.hpp" +#include "relations/ram_computations/rams/tinyram/tinyram_aux.hpp" +#include "common/utils.hpp" + +namespace libsnark { + +tinyram_instruction tinyram_default_instruction = tinyram_instruction(tinyram_opcode_ANSWER, true, 0, 0, 1); + +std::map tinyram_opcode_names = +{ + { tinyram_opcode_AND, "and" }, + { tinyram_opcode_OR, "or" }, + { tinyram_opcode_XOR, "xor" }, + { tinyram_opcode_NOT, "not" }, + { tinyram_opcode_ADD, "add" }, + { tinyram_opcode_SUB, "sub" }, + { tinyram_opcode_MULL, "mull" }, + { tinyram_opcode_UMULH, "umulh" }, + { tinyram_opcode_SMULH, "smulh" }, + { tinyram_opcode_UDIV, "udiv" }, + { tinyram_opcode_UMOD, "umod" }, + { tinyram_opcode_SHL, "shl" }, + { tinyram_opcode_SHR, "shr" }, + + { tinyram_opcode_CMPE, "cmpe" }, + { tinyram_opcode_CMPA, "cmpa" }, + { tinyram_opcode_CMPAE, "cmpae" }, + { tinyram_opcode_CMPG, "cmpg" }, + { tinyram_opcode_CMPGE, "cmpge" }, + + { tinyram_opcode_MOV, "mov" }, + { tinyram_opcode_CMOV, "cmov" }, + { tinyram_opcode_JMP, "jmp" }, + + { tinyram_opcode_CJMP, "cjmp" }, + { tinyram_opcode_CNJMP, "cnjmp" }, + + { tinyram_opcode_10111, "opcode_10111" }, + { tinyram_opcode_11000, "opcode_11000" }, + { tinyram_opcode_11001, "opcode_11001" }, + { tinyram_opcode_STOREB, "store.b" }, + { tinyram_opcode_LOADB, "load.b" }, + + { tinyram_opcode_STOREW, "store.w" }, + { tinyram_opcode_LOADW, "load.w" }, + { tinyram_opcode_READ, "read" }, + { tinyram_opcode_ANSWER, "answer" } +}; + +std::map opcode_args = +{ + { tinyram_opcode_AND, tinyram_opcode_args_des_arg1_arg2 }, + { tinyram_opcode_OR, tinyram_opcode_args_des_arg1_arg2 }, + { tinyram_opcode_XOR, tinyram_opcode_args_des_arg1_arg2 }, + { tinyram_opcode_NOT, tinyram_opcode_args_des_arg2 }, + { tinyram_opcode_ADD, tinyram_opcode_args_des_arg1_arg2 }, + { tinyram_opcode_SUB, tinyram_opcode_args_des_arg1_arg2 }, + { tinyram_opcode_MULL, tinyram_opcode_args_des_arg1_arg2 }, + { tinyram_opcode_UMULH, tinyram_opcode_args_des_arg1_arg2 }, + { tinyram_opcode_SMULH, tinyram_opcode_args_des_arg1_arg2 }, + { tinyram_opcode_UDIV, tinyram_opcode_args_des_arg1_arg2 }, + { tinyram_opcode_UMOD, tinyram_opcode_args_des_arg1_arg2 }, + { tinyram_opcode_SHL, tinyram_opcode_args_des_arg1_arg2 }, + { tinyram_opcode_SHR, tinyram_opcode_args_des_arg1_arg2 }, + { tinyram_opcode_CMPE, tinyram_opcode_args_arg1_arg2 }, + { tinyram_opcode_CMPA, tinyram_opcode_args_arg1_arg2 }, + { tinyram_opcode_CMPAE, tinyram_opcode_args_arg1_arg2 }, + { tinyram_opcode_CMPG, tinyram_opcode_args_arg1_arg2 }, + { tinyram_opcode_CMPGE, tinyram_opcode_args_arg1_arg2 }, + { tinyram_opcode_MOV, tinyram_opcode_args_des_arg2 }, + { tinyram_opcode_CMOV, tinyram_opcode_args_des_arg2 }, + { tinyram_opcode_JMP, tinyram_opcode_args_arg2 }, + { tinyram_opcode_CJMP, tinyram_opcode_args_arg2 }, + { tinyram_opcode_CNJMP, tinyram_opcode_args_arg2 }, + { tinyram_opcode_10111, tinyram_opcode_args_none }, + { tinyram_opcode_11000, tinyram_opcode_args_none }, + { tinyram_opcode_11001, tinyram_opcode_args_none }, + { tinyram_opcode_STOREB, tinyram_opcode_args_arg2_des }, + { tinyram_opcode_LOADB, tinyram_opcode_args_des_arg2 }, + { tinyram_opcode_STOREW, tinyram_opcode_args_arg2_des }, + { tinyram_opcode_LOADW, tinyram_opcode_args_des_arg2 }, + { tinyram_opcode_READ, tinyram_opcode_args_des_arg2 }, + { tinyram_opcode_ANSWER, tinyram_opcode_args_arg2 } +}; + +std::map opcode_values; + +void ensure_tinyram_opcode_value_map() +{ + if (opcode_values.empty()) + { + for (auto it : tinyram_opcode_names) + { + opcode_values[it.second] = it.first; + } + } +} + +std::vector generate_tinyram_prelude(const tinyram_architecture_params &ap) +{ + std::vector result; + const size_t increment = log2(ap.w)/8; + const size_t mem_start = 1ul<<(ap.w-1); + result.emplace_back(tinyram_instruction(tinyram_opcode_STOREW, true, 0, 0, 0)); // 0: store.w 0, r0 + result.emplace_back(tinyram_instruction(tinyram_opcode_MOV, true, 0, 0, mem_start)); // 1: mov r0, 2^{W-1} + result.emplace_back(tinyram_instruction(tinyram_opcode_READ, true, 1, 0, 0)); // 2: read r1, 0 + result.emplace_back(tinyram_instruction(tinyram_opcode_CJMP, true, 0, 0, 7)); // 3: cjmp 7 + result.emplace_back(tinyram_instruction(tinyram_opcode_ADD, true, 0, 0, increment)); // 4: add r0, r0, INCREMENT + result.emplace_back(tinyram_instruction(tinyram_opcode_STOREW, false, 1, 0, 0)); // 5: store.w r0, r1 + result.emplace_back(tinyram_instruction(tinyram_opcode_JMP, true, 0, 0, 2)); // 6: jmp 2 + result.emplace_back(tinyram_instruction(tinyram_opcode_STOREW, true, 0, 0, mem_start)); // 7: store.w 2^{W-1}, r0 + return result; +} + +size_t tinyram_architecture_params::address_size() const +{ + return dwaddr_len(); +} + +size_t tinyram_architecture_params::value_size() const +{ + return 2*w; +} + +size_t tinyram_architecture_params::cpu_state_size() const +{ + return k * w + 2; /* + flag + tape1_exhausted */ +} + +size_t tinyram_architecture_params::initial_pc_addr() const +{ + /* the initial PC address is memory units for the RAM reduction */ + const size_t initial_pc_addr = generate_tinyram_prelude(*this).size(); + return initial_pc_addr; +} + +bit_vector tinyram_architecture_params::initial_cpu_state() const +{ + bit_vector result(this->cpu_state_size(), false); + return result; +} + +memory_contents tinyram_architecture_params::initial_memory_contents(const tinyram_program &program, + const tinyram_input_tape &primary_input) const +{ + // remember that memory consists of 1ul<(tinyram_opcode_ANSWER)); /* assumption: answer is the last */ +} + +size_t tinyram_architecture_params::reg_arg_width() const +{ + return log2(k); +} + +size_t tinyram_architecture_params::instruction_padding_width() const +{ + return 2 * w - (opcode_width() + 1 + 2 * reg_arg_width() + reg_arg_or_imm_width()); +} + +size_t tinyram_architecture_params::reg_arg_or_imm_width() const +{ + return std::max(w, reg_arg_width()); +} + +size_t tinyram_architecture_params::dwaddr_len() const +{ + return w-(log2(w)-2); +} + +size_t tinyram_architecture_params::subaddr_len() const +{ + return log2(w)-2; +} + +size_t tinyram_architecture_params::bytes_in_word() const +{ + return w/8; +} + +size_t tinyram_architecture_params::instr_size() const +{ + return 2*w; +} + +bool tinyram_architecture_params::operator==(const tinyram_architecture_params &other) const +{ + return (this->w == other.w && + this->k == other.k); +} + +std::ostream& operator<<(std::ostream &out, const tinyram_architecture_params &ap) +{ + out << ap.w << "\n"; + out << ap.k << "\n"; + return out; +} + +std::istream& operator>>(std::istream &in, tinyram_architecture_params &ap) +{ + in >> ap.w; + consume_newline(in); + in >> ap.k; + consume_newline(in); + return in; +} + +tinyram_instruction::tinyram_instruction(const tinyram_opcode &opcode, + const bool arg2_is_imm, + const size_t &desidx, + const size_t &arg1idx, + const size_t &arg2idx_or_imm) : + opcode(opcode), + arg2_is_imm(arg2_is_imm), + desidx(desidx), + arg1idx(arg1idx), + arg2idx_or_imm(arg2idx_or_imm) +{ +} + +size_t tinyram_instruction::as_dword(const tinyram_architecture_params &ap) const +{ + size_t result = static_cast(opcode); + result = (result << 1) | (arg2_is_imm ? 1 : 0); + result = (result << log2(ap.k)) | desidx; + result = (result << log2(ap.k)) | arg1idx; + result = (result << (2*ap.w - ap.opcode_width() - 1 - 2 * log2(ap.k))) | arg2idx_or_imm; + + return result; +} + +void tinyram_architecture_params::print() const +{ + printf("* Number of registers (k): %zu\n", k); + printf("* Word size (w): %zu\n", w); +} + +tinyram_instruction random_tinyram_instruction(const tinyram_architecture_params &ap) +{ + const tinyram_opcode opcode = (tinyram_opcode)(std::rand() % (1ul<> instr) + { + print_indent(); + size_t immflag, des, a1; + long long int a2; + if (preprocessed.good()) + { + preprocessed >> immflag >> des >> a1 >> a2; + a2 = ((1ul<> cell) + { + printf("\t%zu", cell); + result.emplace_back(cell); + } + printf("\n"); + + leave_block("Loading tape"); + return result; +} + +} // libsnark diff --git a/privacy/zsl/zsl/snark/libsnark/src/relations/ram_computations/rams/tinyram/tinyram_aux.hpp b/privacy/zsl/zsl/snark/libsnark/src/relations/ram_computations/rams/tinyram/tinyram_aux.hpp new file mode 100644 index 0000000..6f6a79b --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/relations/ram_computations/rams/tinyram/tinyram_aux.hpp @@ -0,0 +1,226 @@ +/** @file + ***************************************************************************** + + Declaration of auxiliary functions for TinyRAM. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef TINYRAM_AUX_HPP_ +#define TINYRAM_AUX_HPP_ + +#include +#include +#include + +#include "common/utils.hpp" +#include "relations/constraint_satisfaction_problems/r1cs/r1cs.hpp" +#include "relations/ram_computations/memory/memory_interface.hpp" +#include "relations/ram_computations/rams/ram_params.hpp" + +namespace libsnark { + +enum tinyram_opcode { + tinyram_opcode_AND = 0b00000, + tinyram_opcode_OR = 0b00001, + tinyram_opcode_XOR = 0b00010, + tinyram_opcode_NOT = 0b00011, + tinyram_opcode_ADD = 0b00100, + tinyram_opcode_SUB = 0b00101, + tinyram_opcode_MULL = 0b00110, + tinyram_opcode_UMULH = 0b00111, + tinyram_opcode_SMULH = 0b01000, + tinyram_opcode_UDIV = 0b01001, + tinyram_opcode_UMOD = 0b01010, + tinyram_opcode_SHL = 0b01011, + tinyram_opcode_SHR = 0b01100, + + tinyram_opcode_CMPE = 0b01101, + tinyram_opcode_CMPA = 0b01110, + tinyram_opcode_CMPAE = 0b01111, + tinyram_opcode_CMPG = 0b10000, + tinyram_opcode_CMPGE = 0b10001, + + tinyram_opcode_MOV = 0b10010, + tinyram_opcode_CMOV = 0b10011, + + tinyram_opcode_JMP = 0b10100, + tinyram_opcode_CJMP = 0b10101, + tinyram_opcode_CNJMP = 0b10110, + + tinyram_opcode_10111 = 0b10111, + tinyram_opcode_11000 = 0b11000, + tinyram_opcode_11001 = 0b11001, + + tinyram_opcode_STOREB = 0b11010, + tinyram_opcode_LOADB = 0b11011, + tinyram_opcode_STOREW = 0b11100, + tinyram_opcode_LOADW = 0b11101, + tinyram_opcode_READ = 0b11110, + tinyram_opcode_ANSWER = 0b11111 +}; + +enum tinyram_opcode_args { + tinyram_opcode_args_des_arg1_arg2 = 1, + tinyram_opcode_args_des_arg2 = 2, + tinyram_opcode_args_arg1_arg2 = 3, + tinyram_opcode_args_arg2 = 4, + tinyram_opcode_args_none = 5, + tinyram_opcode_args_arg2_des = 6 +}; + +/** + * Instructions that may change a register or the flag. + * All other instructions leave all registers and the flag intact. + */ +const static int tinyram_opcodes_register[] = { + tinyram_opcode_AND, + tinyram_opcode_OR, + tinyram_opcode_XOR, + tinyram_opcode_NOT, + tinyram_opcode_ADD, + tinyram_opcode_SUB, + tinyram_opcode_MULL, + tinyram_opcode_UMULH, + tinyram_opcode_SMULH, + tinyram_opcode_UDIV, + tinyram_opcode_UMOD, + tinyram_opcode_SHL, + tinyram_opcode_SHR, + + tinyram_opcode_CMPE, + tinyram_opcode_CMPA, + tinyram_opcode_CMPAE, + tinyram_opcode_CMPG, + tinyram_opcode_CMPGE, + + tinyram_opcode_MOV, + tinyram_opcode_CMOV, + + tinyram_opcode_LOADB, + tinyram_opcode_LOADW, + tinyram_opcode_READ +}; + +/** + * Instructions that modify the program counter. + * All other instructions either advance it (+1) or stall (see below). + */ +const static int tinyram_opcodes_control_flow[] = { + tinyram_opcode_JMP, + tinyram_opcode_CJMP, + tinyram_opcode_CNJMP +}; + +/** + * Instructions that make the program counter stall; + * these are "answer" plus all the undefined opcodes. + */ +const static int tinyram_opcodes_stall[] = { + tinyram_opcode_10111, + tinyram_opcode_11000, + tinyram_opcode_11001, + + tinyram_opcode_ANSWER +}; + +typedef size_t reg_count_t; // type for the number of registers +typedef size_t reg_width_t; // type for the width of a register + +extern std::map tinyram_opcode_names; + +extern std::map opcode_values; + +extern std::map opcode_args; + +void ensure_tinyram_opcode_value_map(); + +class tinyram_program; +typedef std::vector tinyram_input_tape; +typedef typename tinyram_input_tape::const_iterator tinyram_input_tape_iterator; + +class tinyram_architecture_params { +public: + reg_width_t w; /* width of a register */ + reg_count_t k; /* number of registers */ + + tinyram_architecture_params() {}; + tinyram_architecture_params(const reg_width_t w, const reg_count_t k) : w(w), k(k) { assert(w == 1ul << log2(w)); }; + + size_t address_size() const; + size_t value_size() const; + size_t cpu_state_size() const; + size_t initial_pc_addr() const; + + bit_vector initial_cpu_state() const; + memory_contents initial_memory_contents(const tinyram_program &program, + const tinyram_input_tape &primary_input) const; + + size_t opcode_width() const; + size_t reg_arg_width() const; + size_t instruction_padding_width() const; + size_t reg_arg_or_imm_width() const; + + size_t dwaddr_len() const; + size_t subaddr_len() const; + + size_t bytes_in_word() const; + + size_t instr_size() const; + + bool operator==(const tinyram_architecture_params &other) const; + + friend std::ostream& operator<<(std::ostream &out, const tinyram_architecture_params &ap); + friend std::istream& operator>>(std::istream &in, tinyram_architecture_params &ap); + + void print() const; +}; + +/* order everywhere is reversed (i.e. MSB comes first), + corresponding to the order in memory */ + +class tinyram_instruction { +public: + tinyram_opcode opcode; + bool arg2_is_imm; + size_t desidx; + size_t arg1idx; + size_t arg2idx_or_imm; + + tinyram_instruction(const tinyram_opcode &opcode, + const bool arg2_is_imm, + const size_t &desidx, + const size_t &arg1idx, + const size_t &arg2idx_or_imm); + + size_t as_dword(const tinyram_architecture_params &ap) const; +}; + +tinyram_instruction random_tinyram_instruction(const tinyram_architecture_params &ap); + +std::vector generate_tinyram_prelude(const tinyram_architecture_params &ap); +extern tinyram_instruction tinyram_default_instruction; + +class tinyram_program { +public: + std::vector instructions; + size_t size() const { return instructions.size(); } + void add_instruction(const tinyram_instruction &instr); +}; + +tinyram_program load_preprocessed_program(const tinyram_architecture_params &ap, + std::istream &preprocessed); + +memory_store_trace tinyram_boot_trace_from_program_and_input(const tinyram_architecture_params &ap, + const size_t boot_trace_size_bound, + const tinyram_program &program, + const tinyram_input_tape &primary_input); + +tinyram_input_tape load_tape(std::istream &tape); + +} // libsnark + +#endif // TINYRAM_AUX_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/relations/ram_computations/rams/tinyram/tinyram_params.hpp b/privacy/zsl/zsl/snark/libsnark/src/relations/ram_computations/rams/tinyram/tinyram_params.hpp new file mode 100644 index 0000000..35147b4 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/relations/ram_computations/rams/tinyram/tinyram_params.hpp @@ -0,0 +1,38 @@ +/** @file + ***************************************************************************** + + Declaration of public parameters for TinyRAM. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef TINYRAM_PARAMS_HPP_ +#define TINYRAM_PARAMS_HPP_ + +#include "relations/ram_computations/rams/ram_params.hpp" +#include "relations/ram_computations/rams/tinyram/tinyram_aux.hpp" +#include "gadgetlib1/gadgets/cpu_checkers/tinyram/tinyram_cpu_checker.hpp" + +namespace libsnark { + +template +class ram_tinyram { +public: + static size_t timestamp_length; + + typedef FieldT base_field_type; + typedef tinyram_protoboard protoboard_type; + typedef tinyram_gadget gadget_base_type; + typedef tinyram_cpu_checker cpu_checker_type; + typedef tinyram_architecture_params architecture_params_type; +}; + +template +size_t ram_tinyram::timestamp_length = 300; + +} // libsnark + +#endif // TINYRAM_PARAMS_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/relations/variable.hpp b/privacy/zsl/zsl/snark/libsnark/src/relations/variable.hpp new file mode 100644 index 0000000..df82ac4 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/relations/variable.hpp @@ -0,0 +1,213 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for: + - a variable (i.e., x_i), + - a linear term (i.e., a_i * x_i), and + - a linear combination (i.e., sum_i a_i * x_i). + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef VARIABLE_HPP_ +#define VARIABLE_HPP_ + +#include +#include +#include +#include + +namespace libsnark { + +/** + * Mnemonic typedefs. + */ +typedef size_t var_index_t; +typedef long integer_coeff_t; + +/** + * Forward declaration. + */ +template +class linear_term; + +/** + * Forward declaration. + */ +template +class linear_combination; + +/********************************* Variable **********************************/ + +/** + * A variable represents a formal expresison of the form "x_{index}". + */ +template +class variable { +public: + + var_index_t index; + + variable(const var_index_t index = 0) : index(index) {}; + + linear_term operator*(const integer_coeff_t int_coeff) const; + linear_term operator*(const FieldT &field_coeff) const; + + linear_combination operator+(const linear_combination &other) const; + linear_combination operator-(const linear_combination &other) const; + + linear_term operator-() const; + + bool operator==(const variable &other) const; +}; + +template +linear_term operator*(const integer_coeff_t int_coeff, const variable &var); + +template +linear_term operator*(const FieldT &field_coeff, const variable &var); + +template +linear_combination operator+(const integer_coeff_t int_coeff, const variable &var); + +template +linear_combination operator+(const FieldT &field_coeff, const variable &var); + +template +linear_combination operator-(const integer_coeff_t int_coeff, const variable &var); + +template +linear_combination operator-(const FieldT &field_coeff, const variable &var); + + +/****************************** Linear term **********************************/ + +/** + * A linear term represents a formal expression of the form "coeff * x_{index}". + */ +template +class linear_term { +public: + + var_index_t index; + FieldT coeff; + + linear_term() {}; + linear_term(const variable &var); + linear_term(const variable &var, const integer_coeff_t int_coeff); + linear_term(const variable &var, const FieldT &field_coeff); + + linear_term operator*(const integer_coeff_t int_coeff) const; + linear_term operator*(const FieldT &field_coeff) const; + + linear_combination operator+(const linear_combination &other) const; + linear_combination operator-(const linear_combination &other) const; + + linear_term operator-() const; + + bool operator==(const linear_term &other) const; +}; + +template +linear_term operator*(const integer_coeff_t int_coeff, const linear_term <); + +template +linear_term operator*(const FieldT &field_coeff, const linear_term <); + +template +linear_combination operator+(const integer_coeff_t int_coeff, const linear_term <); + +template +linear_combination operator+(const FieldT &field_coeff, const linear_term <); + +template +linear_combination operator-(const integer_coeff_t int_coeff, const linear_term <); + +template +linear_combination operator-(const FieldT &field_coeff, const linear_term <); + + +/***************************** Linear combination ****************************/ + +template +class linear_combination; + +template +std::ostream& operator<<(std::ostream &out, const linear_combination &lc); + +template +std::istream& operator>>(std::istream &in, linear_combination &lc); + +/** + * A linear combination represents a formal expression of the form "sum_i coeff_i * x_{index_i}". + */ +template +class linear_combination { +public: + + std::vector > terms; + + linear_combination() {}; + linear_combination(const integer_coeff_t int_coeff); + linear_combination(const FieldT &field_coeff); + linear_combination(const variable &var); + linear_combination(const linear_term <); + linear_combination(const std::vector > &all_terms); + + /* for supporting range-based for loops over linear_combination */ + typename std::vector >::const_iterator begin() const; + typename std::vector >::const_iterator end() const; + + void add_term(const variable &var); + void add_term(const variable &var, const integer_coeff_t int_coeff); + void add_term(const variable &var, const FieldT &field_coeff); + + void add_term(const linear_term <); + + FieldT evaluate(const std::vector &assignment) const; + + linear_combination operator*(const integer_coeff_t int_coeff) const; + linear_combination operator*(const FieldT &field_coeff) const; + + linear_combination operator+(const linear_combination &other) const; + + linear_combination operator-(const linear_combination &other) const; + linear_combination operator-() const; + + bool operator==(const linear_combination &other) const; + + bool is_valid(const size_t num_variables) const; + + void print(const std::map &variable_annotations = std::map()) const; + void print_with_assignment(const std::vector &full_assignment, const std::map &variable_annotations = std::map()) const; + + friend std::ostream& operator<< (std::ostream &out, const linear_combination &lc); + friend std::istream& operator>> (std::istream &in, linear_combination &lc); +}; + +template +linear_combination operator*(const integer_coeff_t int_coeff, const linear_combination &lc); + +template +linear_combination operator*(const FieldT &field_coeff, const linear_combination &lc); + +template +linear_combination operator+(const integer_coeff_t int_coeff, const linear_combination &lc); + +template +linear_combination operator+(const FieldT &field_coeff, const linear_combination &lc); + +template +linear_combination operator-(const integer_coeff_t int_coeff, const linear_combination &lc); + +template +linear_combination operator-(const FieldT &field_coeff, const linear_combination &lc); + +} // libsnark + +#include "relations/variable.tcc" + +#endif // VARIABLE_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/relations/variable.tcc b/privacy/zsl/zsl/snark/libsnark/src/relations/variable.tcc new file mode 100644 index 0000000..4c4cab9 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/relations/variable.tcc @@ -0,0 +1,512 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for: + - a variable (i.e., x_i), + - a linear term (i.e., a_i * x_i), and + - a linear combination (i.e., sum_i a_i * x_i). + + See variabe.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef VARIABLE_TCC_ +#define VARIABLE_TCC_ + +#include +#include + +#include "algebra/fields/bigint.hpp" + +namespace libsnark { + +template +linear_term variable::operator*(const integer_coeff_t int_coeff) const +{ + return linear_term(*this, int_coeff); +} + +template +linear_term variable::operator*(const FieldT &field_coeff) const +{ + return linear_term(*this, field_coeff); +} + +template +linear_combination variable::operator+(const linear_combination &other) const +{ + linear_combination result; + + result.add_term(*this); + result.terms.insert(result.terms.begin(), other.terms.begin(), other.terms.end()); + + return result; +} + +template +linear_combination variable::operator-(const linear_combination &other) const +{ + return (*this) + (-other); +} + +template +linear_term variable::operator-() const +{ + return linear_term(*this, -FieldT::one()); +} + +template +bool variable::operator==(const variable &other) const +{ + return (this->index == other.index); +} + +template +linear_term operator*(const integer_coeff_t int_coeff, const variable &var) +{ + return linear_term(var, int_coeff); +} + +template +linear_term operator*(const FieldT &field_coeff, const variable &var) +{ + return linear_term(var, field_coeff); +} + +template +linear_combination operator+(const integer_coeff_t int_coeff, const variable &var) +{ + return linear_combination(int_coeff) + var; +} + +template +linear_combination operator+(const FieldT &field_coeff, const variable &var) +{ + return linear_combination(field_coeff) + var; +} + +template +linear_combination operator-(const integer_coeff_t int_coeff, const variable &var) +{ + return linear_combination(int_coeff) - var; +} + +template +linear_combination operator-(const FieldT &field_coeff, const variable &var) +{ + return linear_combination(field_coeff) - var; +} + +template +linear_term::linear_term(const variable &var) : + index(var.index), coeff(FieldT::one()) +{ +} + +template +linear_term::linear_term(const variable &var, const integer_coeff_t int_coeff) : + index(var.index), coeff(FieldT(int_coeff)) +{ +} + +template +linear_term::linear_term(const variable &var, const FieldT &coeff) : + index(var.index), coeff(coeff) +{ +} + +template +linear_term linear_term::operator*(const integer_coeff_t int_coeff) const +{ + return (this->operator*(FieldT(int_coeff))); +} + +template +linear_term linear_term::operator*(const FieldT &field_coeff) const +{ + return linear_term(this->index, field_coeff * this->coeff); +} + +template +linear_combination operator+(const integer_coeff_t int_coeff, const linear_term <) +{ + return linear_combination(int_coeff) + lt; +} + +template +linear_combination operator+(const FieldT &field_coeff, const linear_term <) +{ + return linear_combination(field_coeff) + lt; +} + +template +linear_combination operator-(const integer_coeff_t int_coeff, const linear_term <) +{ + return linear_combination(int_coeff) - lt; +} + +template +linear_combination operator-(const FieldT &field_coeff, const linear_term <) +{ + return linear_combination(field_coeff) - lt; +} + +template +linear_combination linear_term::operator+(const linear_combination &other) const +{ + return linear_combination(*this) + other; +} + +template +linear_combination linear_term::operator-(const linear_combination &other) const +{ + return (*this) + (-other); +} + +template +linear_term linear_term::operator-() const +{ + return linear_term(this->index, -this->coeff); +} + +template +bool linear_term::operator==(const linear_term &other) const +{ + return (this->index == other.index && + this->coeff == other.coeff); +} + +template +linear_term operator*(const integer_coeff_t int_coeff, const linear_term <) +{ + return FieldT(int_coeff) * lt; +} + +template +linear_term operator*(const FieldT &field_coeff, const linear_term <) +{ + return linear_term(lt.index, field_coeff * lt.coeff); +} + +template +linear_combination::linear_combination(const integer_coeff_t int_coeff) +{ + this->add_term(linear_term(0, int_coeff)); +} + +template +linear_combination::linear_combination(const FieldT &field_coeff) +{ + this->add_term(linear_term(0, field_coeff)); +} + +template +linear_combination::linear_combination(const variable &var) +{ + this->add_term(var); +} + +template +linear_combination::linear_combination(const linear_term <) +{ + this->add_term(lt); +} + +template +typename std::vector >::const_iterator linear_combination::begin() const +{ + return terms.begin(); +} + +template +typename std::vector >::const_iterator linear_combination::end() const +{ + return terms.end(); +} + +template +void linear_combination::add_term(const variable &var) +{ + this->terms.emplace_back(linear_term(var.index, FieldT::one())); +} + +template +void linear_combination::add_term(const variable &var, const integer_coeff_t int_coeff) +{ + this->terms.emplace_back(linear_term(var.index, int_coeff)); +} + +template +void linear_combination::add_term(const variable &var, const FieldT &coeff) +{ + this->terms.emplace_back(linear_term(var.index, coeff)); +} + +template +void linear_combination::add_term(const linear_term &other) +{ + this->terms.emplace_back(other); +} + +template +linear_combination linear_combination::operator*(const integer_coeff_t int_coeff) const +{ + return (*this) * FieldT(int_coeff); +} + +template +FieldT linear_combination::evaluate(const std::vector &assignment) const +{ + FieldT acc = FieldT::zero(); + for (auto < : terms) + { + acc += (lt.index == 0 ? FieldT::one() : assignment[lt.index-1]) * lt.coeff; + } + return acc; +} + +template +linear_combination linear_combination::operator*(const FieldT &field_coeff) const +{ + linear_combination result; + result.terms.reserve(this->terms.size()); + for (const linear_term < : this->terms) + { + result.terms.emplace_back(lt * field_coeff); + } + return result; +} + +template +linear_combination linear_combination::operator+(const linear_combination &other) const +{ + linear_combination result; + + auto it1 = this->terms.begin(); + auto it2 = other.terms.begin(); + + /* invariant: it1 and it2 always point to unprocessed items in the corresponding linear combinations */ + while (it1 != this->terms.end() && it2 != other.terms.end()) + { + if (it1->index < it2->index) + { + result.terms.emplace_back(*it1); + ++it1; + } + else if (it1->index > it2->index) + { + result.terms.emplace_back(*it2); + ++it2; + } + else + { + /* it1->index == it2->index */ + result.terms.emplace_back(linear_term(variable(it1->index), it1->coeff + it2->coeff)); + ++it1; + ++it2; + } + } + + if (it1 != this->terms.end()) + { + result.terms.insert(result.terms.end(), it1, this->terms.end()); + } + else + { + result.terms.insert(result.terms.end(), it2, other.terms.end()); + } + + return result; +} + +template +linear_combination linear_combination::operator-(const linear_combination &other) const +{ + return (*this) + (-other); +} + +template +linear_combination linear_combination::operator-() const +{ + return (*this) * (-FieldT::one()); +} + +template +bool linear_combination::operator==(const linear_combination &other) const +{ + return (this->terms == other.terms); +} + +template +bool linear_combination::is_valid(const size_t num_variables) const +{ + /* check that all terms in linear combination are sorted */ + for (size_t i = 1; i < terms.size(); ++i) + { + if (terms[i-1].index >= terms[i].index) + { + return false; + } + } + + /* check that the variables are in proper range. as the variables + are sorted, it suffices to check the last term */ + if ((--terms.end())->index >= num_variables) + { + return false; + } + + return true; +} + +template +void linear_combination::print(const std::map &variable_annotations) const +{ + for (auto < : terms) + { + if (lt.index == 0) + { + printf(" 1 * "); + lt.coeff.print(); + } + else + { + auto it = variable_annotations.find(lt.index); + printf(" x_%zu (%s) * ", lt.index, (it == variable_annotations.end() ? "no annotation" : it->second.c_str())); + lt.coeff.print(); + } + } +} + +template +void linear_combination::print_with_assignment(const std::vector &full_assignment, const std::map &variable_annotations) const +{ + for (auto < : terms) + { + if (lt.index == 0) + { + printf(" 1 * "); + lt.coeff.print(); + } + else + { + printf(" x_%zu * ", lt.index); + lt.coeff.print(); + + auto it = variable_annotations.find(lt.index); + printf(" where x_%zu (%s) was assigned value ", lt.index, + (it == variable_annotations.end() ? "no annotation" : it->second.c_str())); + full_assignment[lt.index-1].print(); + printf(" i.e. negative of "); + (-full_assignment[lt.index-1]).print(); + } + } +} + +template +std::ostream& operator<<(std::ostream &out, const linear_combination &lc) +{ + out << lc.terms.size() << "\n"; + for (const linear_term& lt : lc.terms) + { + out << lt.index << "\n"; + out << lt.coeff << OUTPUT_NEWLINE; + } + + return out; +} + +template +std::istream& operator>>(std::istream &in, linear_combination &lc) +{ + lc.terms.clear(); + + size_t s; + in >> s; + + consume_newline(in); + + lc.terms.reserve(s); + + for (size_t i = 0; i < s; ++i) + { + linear_term lt; + in >> lt.index; + consume_newline(in); + in >> lt.coeff; + consume_OUTPUT_NEWLINE(in); + lc.terms.emplace_back(lt); + } + + return in; +} + +template +linear_combination operator*(const integer_coeff_t int_coeff, const linear_combination &lc) +{ + return lc * int_coeff; +} + +template +linear_combination operator*(const FieldT &field_coeff, const linear_combination &lc) +{ + return lc * field_coeff; +} + +template +linear_combination operator+(const integer_coeff_t int_coeff, const linear_combination &lc) +{ + return linear_combination(int_coeff) + lc; +} + +template +linear_combination operator+(const FieldT &field_coeff, const linear_combination &lc) +{ + return linear_combination(field_coeff) + lc; +} + +template +linear_combination operator-(const integer_coeff_t int_coeff, const linear_combination &lc) +{ + return linear_combination(int_coeff) - lc; +} + +template +linear_combination operator-(const FieldT &field_coeff, const linear_combination &lc) +{ + return linear_combination(field_coeff) - lc; +} + +template +linear_combination::linear_combination(const std::vector > &all_terms) +{ + if (all_terms.empty()) + { + return; + } + + terms = all_terms; + std::sort(terms.begin(), terms.end(), [](linear_term a, linear_term b) { return a.index < b.index; }); + + auto result_it = terms.begin(); + for (auto it = ++terms.begin(); it != terms.end(); ++it) + { + if (it->index == result_it->index) + { + result_it->coeff += it->coeff; + } + else + { + *(++result_it) = *it; + } + } + terms.resize((result_it - terms.begin()) + 1); +} + +} // libsnark + +#endif // VARIABLE_TCC diff --git a/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/pcd/r1cs_pcd/compliance_predicate/compliance_predicate.hpp b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/pcd/r1cs_pcd/compliance_predicate/compliance_predicate.hpp new file mode 100644 index 0000000..4488d48 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/pcd/r1cs_pcd/compliance_predicate/compliance_predicate.hpp @@ -0,0 +1,160 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for a compliance predicate for R1CS PCD. + + A compliance predicate specifies a local invariant to be enforced, by PCD, + throughout a dynamic distributed computation. A compliance predicate + receives input messages, local data, and an output message (and perhaps some + other auxiliary information), and then either accepts or rejects. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef COMPLIANCE_PREDICATE_HPP_ +#define COMPLIANCE_PREDICATE_HPP_ + +#include "relations/constraint_satisfaction_problems/r1cs/r1cs.hpp" + +namespace libsnark { + +/********************************* Message ***********************************/ + +/** + * A message for R1CS PCD. + * + * It is a pair, consisting of + * - a type (a positive integer), and + * - a payload (a vector of field elements). + */ +template +class r1cs_pcd_message { +public: + size_t type; + + r1cs_pcd_message(const size_t type); + virtual r1cs_variable_assignment payload_as_r1cs_variable_assignment() const = 0; + r1cs_variable_assignment as_r1cs_variable_assignment() const; + + virtual void print() const; + virtual ~r1cs_pcd_message() = default; +}; + +/******************************* Local data **********************************/ + +/** + * A local data for R1CS PCD. + */ +template +class r1cs_pcd_local_data { +public: + r1cs_pcd_local_data() = default; + virtual r1cs_variable_assignment as_r1cs_variable_assignment() const = 0; + virtual ~r1cs_pcd_local_data() = default; +}; + +/******************************** Witness ************************************/ + +template +using r1cs_pcd_witness = std::vector; + +/*************************** Compliance predicate ****************************/ + +template +class r1cs_pcd_compliance_predicate; + +template +std::ostream& operator<<(std::ostream &out, const r1cs_pcd_compliance_predicate &cp); + +template +std::istream& operator>>(std::istream &in, r1cs_pcd_compliance_predicate &cp); + +/** + * A compliance predicate for R1CS PCD. + * + * It is a wrapper around R1CS that also specifies how to parse a + * variable assignment as: + * - output message (the input) + * - some number of input messages (part of the witness) + * - local data (also part of the witness) + * - auxiliary information (the remaining variables of the witness) + * + * A compliance predicate also has a type, allegedly the same + * as the type of the output message. + * + * The input wires of R1CS appear in the following order: + * - (1 + outgoing_message_payload_length) wires for outgoing message + * - 1 wire for arity (allegedly, 0 <= arity <= max_arity) + * - for i = 0, ..., max_arity-1: + * - (1 + incoming_message_payload_lengths[i]) wires for i-th message of + * the input (in the array that's padded to max_arity messages) + * - local_data_length wires for local data + * + * The rest witness_length wires of the R1CS constitute the witness. + * + * To allow for optimizations, the compliance predicate also + * specififies a flag, called relies_on_same_type_inputs, denoting + * whether the predicate works under the assumption that all input + * messages have the same type. In such case a member + * accepted_input_types lists all types accepted by the predicate + * (accepted_input_types has no meaning if + * relies_on_same_type_inputs=false). + */ + +template +class r1cs_pcd_compliance_predicate { +public: + + size_t name; + size_t type; + + r1cs_constraint_system constraint_system; + + size_t outgoing_message_payload_length; + size_t max_arity; + std::vector incoming_message_payload_lengths; + size_t local_data_length; + size_t witness_length; + + bool relies_on_same_type_inputs; + std::set accepted_input_types; + + r1cs_pcd_compliance_predicate() = default; + r1cs_pcd_compliance_predicate(r1cs_pcd_compliance_predicate &&other) = default; + r1cs_pcd_compliance_predicate(const r1cs_pcd_compliance_predicate &other) = default; + r1cs_pcd_compliance_predicate(const size_t name, + const size_t type, + const r1cs_constraint_system &constraint_system, + const size_t outgoing_message_payload_length, + const size_t max_arity, + const std::vector &incoming_message_payload_lengths, + const size_t local_data_length, + const size_t witness_length, + const bool relies_on_same_type_inputs, + const std::set accepted_input_types = std::set()); + + r1cs_pcd_compliance_predicate & operator=(const r1cs_pcd_compliance_predicate &other) = default; + + bool is_well_formed() const; + bool has_equal_input_and_output_lengths() const; + bool has_equal_input_lengths() const; + + bool is_satisfied(const std::shared_ptr > &outgoing_message, + const std::vector > > &incoming_messages, + const std::shared_ptr > &local_data, + const r1cs_pcd_witness &witness) const; + + bool operator==(const r1cs_pcd_compliance_predicate &other) const; + friend std::ostream& operator<< (std::ostream &out, const r1cs_pcd_compliance_predicate &cp); + friend std::istream& operator>> (std::istream &in, r1cs_pcd_compliance_predicate &cp); +}; + + +} // libsnark + +#include "zk_proof_systems/pcd/r1cs_pcd/compliance_predicate/compliance_predicate.tcc" + +#endif // COMPLIANCE_PREDICATE_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/pcd/r1cs_pcd/compliance_predicate/compliance_predicate.tcc b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/pcd/r1cs_pcd/compliance_predicate/compliance_predicate.tcc new file mode 100644 index 0000000..bca6b9b --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/pcd/r1cs_pcd/compliance_predicate/compliance_predicate.tcc @@ -0,0 +1,235 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for a compliance predicate for R1CS PCD. + + See compliance_predicate.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef COMPLIANCE_PREDICATE_TCC_ +#define COMPLIANCE_PREDICATE_TCC_ + +#include "common/utils.hpp" +#include "zk_proof_systems/pcd/r1cs_pcd/r1cs_sp_ppzkpcd/r1cs_sp_ppzkpcd_params.hpp" + +namespace libsnark { + +template +class r1cs_pcd_compliance_predicate_primary_input; + +template +class r1cs_pcd_compliance_predicate_auxiliary_input; + +template +r1cs_variable_assignment r1cs_pcd_message::as_r1cs_variable_assignment() const +{ + r1cs_variable_assignment result = this->payload_as_r1cs_variable_assignment(); + result.insert(result.begin(), FieldT(this->type)); + return result; +} + +template +r1cs_pcd_message::r1cs_pcd_message(const size_t type) : type(type) +{ +} + +template +void r1cs_pcd_message::print() const +{ + printf("PCD message (default print routines):\n"); + printf(" Type: %zu\n", this->type); + + printf(" Payload\n"); + const r1cs_variable_assignment payload = this->payload_as_r1cs_variable_assignment(); + for (auto &elt: payload) + { + elt.print(); + } +} + +template +r1cs_pcd_compliance_predicate::r1cs_pcd_compliance_predicate(const size_t name, + const size_t type, + const r1cs_constraint_system &constraint_system, + const size_t outgoing_message_payload_length, + const size_t max_arity, + const std::vector &incoming_message_payload_lengths, + const size_t local_data_length, + const size_t witness_length, + const bool relies_on_same_type_inputs, + const std::set accepted_input_types) : + name(name), + type(type), + constraint_system(constraint_system), + outgoing_message_payload_length(outgoing_message_payload_length), + max_arity(max_arity), + incoming_message_payload_lengths(incoming_message_payload_lengths), + local_data_length(local_data_length), + witness_length(witness_length), + relies_on_same_type_inputs(relies_on_same_type_inputs), + accepted_input_types(accepted_input_types) +{ + assert(max_arity == incoming_message_payload_lengths.size()); +} + +template +bool r1cs_pcd_compliance_predicate::is_well_formed() const +{ + const bool type_not_zero = (type != 0); + const bool incoming_message_payload_lengths_well_specified = (incoming_message_payload_lengths.size() == max_arity); + + size_t all_message_payload_lengths = outgoing_message_payload_length; + for (size_t i = 0; i < incoming_message_payload_lengths.size(); ++i) + { + all_message_payload_lengths += incoming_message_payload_lengths[i]; + } + const size_t type_vec_length = max_arity+1; + const size_t arity_length = 1; + + const bool correct_num_inputs = ((outgoing_message_payload_length + 1) == constraint_system.num_inputs()); + const bool correct_num_variables = ((all_message_payload_lengths + local_data_length + type_vec_length + arity_length + witness_length) == constraint_system.num_variables()); + +#ifdef DEBUG + printf("outgoing_message_payload_length: %zu\n", outgoing_message_payload_length); + printf("incoming_message_payload_lengths:"); + for (auto l : incoming_message_payload_lengths) + { + printf(" %zu", l); + } + printf("\n"); + printf("type_not_zero: %d\n", type_not_zero); + printf("incoming_message_payload_lengths_well_specified: %d\n", incoming_message_payload_lengths_well_specified); + printf("correct_num_inputs: %d (outgoing_message_payload_length = %zu, constraint_system.num_inputs() = %zu)\n", + correct_num_inputs, outgoing_message_payload_length, constraint_system.num_inputs()); + printf("correct_num_variables: %d (all_message_payload_lengths = %zu, local_data_length = %zu, type_vec_length = %zu, arity_length = %zu, witness_length = %zu, constraint_system.num_variables() = %zu)\n", + correct_num_variables, + all_message_payload_lengths, local_data_length, type_vec_length, arity_length, witness_length, + constraint_system.num_variables()); +#endif + + return (type_not_zero && incoming_message_payload_lengths_well_specified && correct_num_inputs && correct_num_variables); +} + +template +bool r1cs_pcd_compliance_predicate::has_equal_input_and_output_lengths() const +{ + for (size_t i = 0; i < incoming_message_payload_lengths.size(); ++i) + { + if (incoming_message_payload_lengths[i] != outgoing_message_payload_length) + { + return false; + } + } + + return true; +} + +template +bool r1cs_pcd_compliance_predicate::has_equal_input_lengths() const +{ + for (size_t i = 1; i < incoming_message_payload_lengths.size(); ++i) + { + if (incoming_message_payload_lengths[i] != incoming_message_payload_lengths[0]) + { + return false; + } + } + + return true; +} + +template +bool r1cs_pcd_compliance_predicate::operator==(const r1cs_pcd_compliance_predicate &other) const +{ + return (this->name == other.name && + this->type == other.type && + this->constraint_system == other.constraint_system && + this->outgoing_message_payload_length == other.outgoing_message_payload_length && + this->max_arity == other.max_arity && + this->incoming_message_payload_lengths == other.incoming_message_payload_lengths && + this->local_data_length == other.local_data_length && + this->witness_length == other.witness_length && + this->relies_on_same_type_inputs == other.relies_on_same_type_inputs && + this->accepted_input_types == other.accepted_input_types); +} + +template +std::ostream& operator<<(std::ostream &out, const r1cs_pcd_compliance_predicate &cp) +{ + out << cp.name << "\n"; + out << cp.type << "\n"; + out << cp.max_arity << "\n"; + assert(cp.max_arity == cp.incoming_message_payload_lengths.size()); + for (size_t i = 0; i < cp.max_arity; ++i) + { + out << cp.incoming_message_payload_lengths[i] << "\n"; + } + out << cp.outgoing_message_payload_length << "\n"; + out << cp.local_data_length << "\n"; + out << cp.witness_length << "\n"; + output_bool(out, cp.relies_on_same_type_inputs); + out << cp.accepted_input_types << "\n"; + out << cp.constraint_system << "\n"; + + return out; +} + +template +std::istream& operator>>(std::istream &in, r1cs_pcd_compliance_predicate &cp) +{ + in >> cp.name; + consume_newline(in); + in >> cp.type; + consume_newline(in); + in >> cp.max_arity; + consume_newline(in); + cp.incoming_message_payload_lengths.resize(cp.max_arity); + for (size_t i = 0; i < cp.max_arity; ++i) + { + in >> cp.incoming_message_payload_lengths[i]; + consume_newline(in); + } + in >> cp.outgoing_message_payload_length; + consume_newline(in); + in >> cp.local_data_length; + consume_newline(in); + in >> cp.witness_length; + consume_newline(in); + input_bool(in, cp.relies_on_same_type_inputs); + in >> cp.accepted_input_types; + consume_newline(in); + in >> cp.constraint_system; + consume_newline(in); + + return in; +} + +template +bool r1cs_pcd_compliance_predicate::is_satisfied(const std::shared_ptr > &outgoing_message, + const std::vector > > &incoming_messages, + const std::shared_ptr > &local_data, + const r1cs_pcd_witness &witness) const +{ + assert(outgoing_message.payload_as_r1cs_variable_assignment().size() == outgoing_message_payload_length); + assert(incoming_messages.size() <= max_arity); + for (size_t i = 0; i < incoming_messages.size(); ++i) + { + assert(incoming_messages[i].payload_as_r1cs_variable_assignment().size() == incoming_message_payload_lengths[i]); + } + assert(local_data.as_r1cs_variable_assignment().size() == local_data_length); + + r1cs_pcd_compliance_predicate_primary_input cp_primary_input(outgoing_message); + r1cs_pcd_compliance_predicate_auxiliary_input cp_auxiliary_input(incoming_messages, local_data, witness); + + return constraint_system.is_satisfied(cp_primary_input.as_r1cs_primary_input(), + cp_auxiliary_input.as_r1cs_auxiliary_input(incoming_message_payload_lengths)); +} + +} // libsnark + +#endif // COMPLIANCE_PREDICATE_TCC_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/pcd/r1cs_pcd/compliance_predicate/cp_handler.hpp b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/pcd/r1cs_pcd/compliance_predicate/cp_handler.hpp new file mode 100644 index 0000000..5b841c0 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/pcd/r1cs_pcd/compliance_predicate/cp_handler.hpp @@ -0,0 +1,114 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for a compliance predicate handler. + + A compliance predicate handler is a base class for creating compliance predicates. + It relies on classes declared in gadgetlib1. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef CP_HANDLER_HPP_ +#define CP_HANDLER_HPP_ + +#include "zk_proof_systems/pcd/r1cs_pcd/compliance_predicate/compliance_predicate.hpp" +#include "gadgetlib1/protoboard.hpp" + +namespace libsnark { + +/***************************** Message variable ******************************/ + +/** + * A variable to represent an r1cs_pcd_message. + */ +template +class r1cs_pcd_message_variable : public gadget { +protected: + size_t num_vars_at_construction; +public: + + pb_variable type; + + pb_variable_array all_vars; + + r1cs_pcd_message_variable(protoboard &pb, + const std::string &annotation_prefix); + void update_all_vars(); + + void generate_r1cs_witness(const std::shared_ptr > &message); + virtual std::shared_ptr > get_message() const = 0; + + virtual ~r1cs_pcd_message_variable() = default; +}; +/*************************** Local data variable *****************************/ + +/** + * A variable to represent an r1cs_pcd_local_data. + */ +template +class r1cs_pcd_local_data_variable : public gadget { +protected: + size_t num_vars_at_construction; +public: + + pb_variable_array all_vars; + + r1cs_pcd_local_data_variable(protoboard &pb, + const std::string &annotation_prefix); + void update_all_vars(); + + void generate_r1cs_witness(const std::shared_ptr > &local_data); + + virtual ~r1cs_pcd_local_data_variable() = default; +}; + +/*********************** Compliance predicate handler ************************/ + +/** + * A base class for creating compliance predicates. + */ +template +class compliance_predicate_handler { +protected: + protoboardT pb; + + std::shared_ptr > outgoing_message; + pb_variable arity; + std::vector > > incoming_messages; + std::shared_ptr > local_data; +public: + const size_t name; + const size_t type; + const size_t max_arity; + const bool relies_on_same_type_inputs; + const std::set accepted_input_types; + + compliance_predicate_handler(const protoboardT &pb, + const size_t name, + const size_t type, + const size_t max_arity, + const bool relies_on_same_type_inputs, + const std::set accepted_input_types = std::set()); + virtual void generate_r1cs_constraints() = 0; + virtual void generate_r1cs_witness(const std::vector > > &incoming_message_values, + const std::shared_ptr > &local_data_value); + + r1cs_pcd_compliance_predicate get_compliance_predicate() const; + r1cs_variable_assignment get_full_variable_assignment() const; + + std::shared_ptr > get_outgoing_message() const; + size_t get_arity() const; + std::shared_ptr > get_incoming_message(const size_t message_idx) const; + std::shared_ptr > get_local_data() const; + r1cs_variable_assignment get_witness() const; +}; + +} // libsnark + +#include "zk_proof_systems/pcd/r1cs_pcd/compliance_predicate/cp_handler.tcc" + +#endif // CP_HANDLER_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/pcd/r1cs_pcd/compliance_predicate/cp_handler.tcc b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/pcd/r1cs_pcd/compliance_predicate/cp_handler.tcc new file mode 100644 index 0000000..431134e --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/pcd/r1cs_pcd/compliance_predicate/cp_handler.tcc @@ -0,0 +1,189 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for a compliance predicate handler. + + See cp_handler.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef CP_HANDLER_TCC_ +#define CP_HANDLER_TCC_ + +#include + +namespace libsnark { + +template +r1cs_pcd_message_variable::r1cs_pcd_message_variable(protoboard &pb, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix) +{ + type.allocate(pb, FMT(annotation_prefix, " type")); + all_vars.emplace_back(type); + + num_vars_at_construction = pb.num_variables(); +} + +template +void r1cs_pcd_message_variable::update_all_vars() +{ + /* NOTE: this assumes that r1cs_pcd_message_variable has been the + * only gadget allocating variables on the protoboard and needs to + * be updated, e.g., in multicore variable allocation scenario. */ + + for (size_t var_idx = num_vars_at_construction + 1; var_idx <= this->pb.num_variables(); ++var_idx) + { + all_vars.emplace_back(pb_variable(var_idx)); + } +} + +template +void r1cs_pcd_message_variable::generate_r1cs_witness(const std::shared_ptr > &message) +{ + all_vars.fill_with_field_elements(this->pb, message->as_r1cs_variable_assignment()); +} + +template +r1cs_pcd_local_data_variable::r1cs_pcd_local_data_variable(protoboard &pb, + const std::string &annotation_prefix) : + gadget(pb, annotation_prefix) +{ + num_vars_at_construction = pb.num_variables(); +} + +template +void r1cs_pcd_local_data_variable::update_all_vars() +{ + /* (the same NOTE as for r1cs_message_variable applies) */ + + for (size_t var_idx = num_vars_at_construction + 1; var_idx <= this->pb.num_variables(); ++var_idx) + { + all_vars.emplace_back(pb_variable(var_idx)); + } +} + +template +void r1cs_pcd_local_data_variable::generate_r1cs_witness(const std::shared_ptr > &local_data) +{ + all_vars.fill_with_field_elements(this->pb, local_data->as_r1cs_variable_assignment()); +} + +template +compliance_predicate_handler::compliance_predicate_handler(const protoboardT &pb, + const size_t name, + const size_t type, + const size_t max_arity, + const bool relies_on_same_type_inputs, + const std::set accepted_input_types) : + pb(pb), name(name), type(type), max_arity(max_arity), relies_on_same_type_inputs(relies_on_same_type_inputs), + accepted_input_types(accepted_input_types) +{ + incoming_messages.resize(max_arity); +} + +template +void compliance_predicate_handler::generate_r1cs_witness(const std::vector > > &incoming_message_values, + const std::shared_ptr > &local_data_value) +{ + pb.clear_values(); + pb.val(outgoing_message->type) = FieldT(type); + pb.val(arity) = FieldT(incoming_message_values.size()); + + for (size_t i = 0; i < incoming_message_values.size(); ++i) + { + incoming_messages[i]->generate_r1cs_witness(incoming_message_values[i]); + } + + local_data->generate_r1cs_witness(local_data_value); +} + + +template +r1cs_pcd_compliance_predicate compliance_predicate_handler::get_compliance_predicate() const +{ + assert(incoming_messages.size() == max_arity); + + const size_t outgoing_message_payload_length = outgoing_message->all_vars.size() - 1; + + std::vector incoming_message_payload_lengths(max_arity); + std::transform(incoming_messages.begin(), incoming_messages.end(), + incoming_message_payload_lengths.begin(), + [] (const std::shared_ptr > &msg) { return msg->all_vars.size() - 1; }); + + const size_t local_data_length = local_data->all_vars.size(); + + const size_t all_but_witness_length = ((1 + outgoing_message_payload_length) + 1 + + (max_arity + std::accumulate(incoming_message_payload_lengths.begin(), + incoming_message_payload_lengths.end(), 0)) + + local_data_length); + const size_t witness_length = pb.num_variables() - all_but_witness_length; + + r1cs_constraint_system constraint_system = pb.get_constraint_system(); + constraint_system.primary_input_size = 1 + outgoing_message_payload_length; + constraint_system.auxiliary_input_size = pb.num_variables() - constraint_system.primary_input_size; + + return r1cs_pcd_compliance_predicate(name, + type, + constraint_system, + outgoing_message_payload_length, + max_arity, + incoming_message_payload_lengths, + local_data_length, + witness_length, + relies_on_same_type_inputs, + accepted_input_types); +} + +template +r1cs_variable_assignment compliance_predicate_handler::get_full_variable_assignment() const +{ + return pb.full_variable_assignment(); +} + +template +std::shared_ptr > compliance_predicate_handler::get_outgoing_message() const +{ + return outgoing_message->get_message(); +} + +template +size_t compliance_predicate_handler::get_arity() const +{ + return pb.val(arity).as_ulong(); +} + +template +std::shared_ptr > compliance_predicate_handler::get_incoming_message(const size_t message_idx) const +{ + assert(message_idx < max_arity); + return incoming_messages[message_idx]->get_message(); +} + +template +std::shared_ptr > compliance_predicate_handler::get_local_data() const +{ + return local_data->get_local_data(); +} + +template +r1cs_pcd_witness compliance_predicate_handler::get_witness() const +{ + const r1cs_variable_assignment va = pb.full_variable_assignment(); + // outgoing_message + arity + incoming_messages + local_data + const size_t witness_pos = (outgoing_message->all_vars.size() + 1 + + std::accumulate(incoming_messages.begin(), incoming_messages.end(), + 0, [](size_t acc, const std::shared_ptr > &msg) { + return acc + msg->all_vars.size(); }) + + local_data->all_vars.size()); + + return r1cs_variable_assignment(va.begin() + witness_pos, va.end()); +} + +} // libsnark + +#endif // CP_HANDLER_TCC_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/pcd/r1cs_pcd/compliance_predicate/examples/tally_cp.hpp b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/pcd/r1cs_pcd/compliance_predicate/examples/tally_cp.hpp new file mode 100644 index 0000000..2a6f237 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/pcd/r1cs_pcd/compliance_predicate/examples/tally_cp.hpp @@ -0,0 +1,110 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for the tally compliance predicate. + + The tally compliance predicate has two purposes: + (1) it exemplifies the use of interfaces declared in cp_handler.hpp, and + (2) it enables us to test r1cs_pcd functionalities. + + See + - src/zk_proof_systems/pcd/r1cs_pcd/r1cs_sp_ppzkpcd/examples/run_r1cs_sp_ppzkpcd.hpp + - src/zk_proof_systems/pcd/r1cs_pcd/r1cs_mp_ppzkpcd/examples/run_r1cs_mp_ppzkpcd.hpp + for code that uses the tally compliance predicate. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef TALLY_CP_HPP_ +#define TALLY_CP_HPP_ + +#include "gadgetlib1/gadgets/basic_gadgets.hpp" +#include "zk_proof_systems/pcd/r1cs_pcd/compliance_predicate/compliance_predicate.hpp" +#include "zk_proof_systems/pcd/r1cs_pcd/compliance_predicate/cp_handler.hpp" + +namespace libsnark { + +/** + * Subclasses a R1CS PCD message to the tally compliance predicate. + */ +template +class tally_pcd_message : public r1cs_pcd_message { +public: + size_t wordsize; + + size_t sum; + size_t count; + + tally_pcd_message(const size_t type, + const size_t wordsize, + const size_t sum, + const size_t count); + r1cs_variable_assignment payload_as_r1cs_variable_assignment() const; + void print() const; + + ~tally_pcd_message() = default; +}; + +template +class tally_pcd_local_data : public r1cs_pcd_local_data { +public: + size_t summand; + + tally_pcd_local_data(const size_t summand); + r1cs_variable_assignment as_r1cs_variable_assignment() const; + void print() const; + + ~tally_pcd_local_data() = default; +}; + +/** + * Subclass a R1CS compliance predicate handler to the tally compliance predicate handler. + */ +template +class tally_cp_handler : public compliance_predicate_handler > { +public: + typedef compliance_predicate_handler > base_handler; + pb_variable_array incoming_types; + + pb_variable sum_out_packed; + pb_variable count_out_packed; + pb_variable_array sum_in_packed; + pb_variable_array count_in_packed; + + pb_variable_array sum_in_packed_aux; + pb_variable_array count_in_packed_aux; + + std::shared_ptr > unpack_sum_out; + std::shared_ptr > unpack_count_out; + std::vector > pack_sum_in; + std::vector > pack_count_in; + + pb_variable type_val_inner_product; + std::shared_ptr > compute_type_val_inner_product; + + pb_variable_array arity_indicators; + + size_t wordsize; + size_t message_length; + + tally_cp_handler(const size_t type, + const size_t max_arity, + const size_t wordsize, + const bool relies_on_same_type_inputs = false, + const std::set accepted_input_types = std::set()); + + void generate_r1cs_constraints(); + void generate_r1cs_witness(const std::vector > > &incoming_messages, + const std::shared_ptr > &local_data); + + std::shared_ptr > get_base_case_message() const; +}; + +} // libsnark + +#include "zk_proof_systems/pcd/r1cs_pcd/compliance_predicate/examples/tally_cp.tcc" + +#endif // TALLY_CP_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/pcd/r1cs_pcd/compliance_predicate/examples/tally_cp.tcc b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/pcd/r1cs_pcd/compliance_predicate/examples/tally_cp.tcc new file mode 100644 index 0000000..7712d75 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/pcd/r1cs_pcd/compliance_predicate/examples/tally_cp.tcc @@ -0,0 +1,276 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for the tally compliance predicate. + + See tally_cp.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef TALLY_CP_TCC_ +#define TALLY_CP_TCC_ + +#include +#include + +namespace libsnark { + +template +tally_pcd_message::tally_pcd_message(const size_t type, + const size_t wordsize, + const size_t sum, + const size_t count) : + r1cs_pcd_message(type), wordsize(wordsize), sum(sum), count(count) +{ +} + +template +r1cs_variable_assignment tally_pcd_message::payload_as_r1cs_variable_assignment() const +{ + std::function bit_to_FieldT = [] (const bool bit) { return bit ? FieldT::one() : FieldT::zero(); }; + + const bit_vector sum_bits = convert_field_element_to_bit_vector(sum, wordsize); + const bit_vector count_bits = convert_field_element_to_bit_vector(count, wordsize); + + r1cs_variable_assignment result(2 * wordsize); + std::transform(sum_bits.begin(), sum_bits.end(), result.begin() , bit_to_FieldT); + std::transform(count_bits.begin(), count_bits.end(), result.begin() + wordsize, bit_to_FieldT); + + return result; +} + +template +void tally_pcd_message::print() const +{ + printf("Tally message of type %zu:\n", this->type); + printf(" wordsize: %zu\n", wordsize); + printf(" sum: %zu\n", sum); + printf(" count: %zu\n", count); +} + +template +tally_pcd_local_data::tally_pcd_local_data(const size_t summand) : + summand(summand) +{ +} + +template +r1cs_variable_assignment tally_pcd_local_data::as_r1cs_variable_assignment() const +{ + const r1cs_variable_assignment result = { FieldT(summand) }; + return result; +} + +template +void tally_pcd_local_data::print() const +{ + printf("Tally PCD local data:\n"); + printf(" summand: %zu\n", summand); +} + +template +class tally_pcd_message_variable: public r1cs_pcd_message_variable { +public: + pb_variable_array sum_bits; + pb_variable_array count_bits; + size_t wordsize; + + tally_pcd_message_variable(protoboard &pb, + const size_t wordsize, + const std::string &annotation_prefix) : + r1cs_pcd_message_variable(pb, annotation_prefix), wordsize(wordsize) + { + sum_bits.allocate(pb, wordsize, FMT(annotation_prefix, " sum_bits")); + count_bits.allocate(pb, wordsize, FMT(annotation_prefix, " count_bits")); + + this->update_all_vars(); + } + + std::shared_ptr > get_message() const + { + const size_t type_val = this->pb.val(this->type).as_ulong(); + const size_t sum_val = sum_bits.get_field_element_from_bits(this->pb).as_ulong(); + const size_t count_val = count_bits.get_field_element_from_bits(this->pb).as_ulong(); + + std::shared_ptr > result; + result.reset(new tally_pcd_message(type_val, wordsize, sum_val, count_val)); + return result; + } + + ~tally_pcd_message_variable() = default; +}; + +template +class tally_pcd_local_data_variable : public r1cs_pcd_local_data_variable { +public: + + pb_variable summand; + + tally_pcd_local_data_variable(protoboard &pb, + const std::string &annotation_prefix) : + r1cs_pcd_local_data_variable(pb, annotation_prefix) + { + summand.allocate(pb, FMT(annotation_prefix, " summand")); + + this->update_all_vars(); + } + + std::shared_ptr > get_local_data() const + { + const size_t summand_val = this->pb.val(summand).as_ulong(); + + std::shared_ptr > result; + result.reset(new tally_pcd_local_data(summand_val)); + return result; + } + + ~tally_pcd_local_data_variable() = default; +}; + +template +tally_cp_handler::tally_cp_handler(const size_t type, const size_t max_arity, const size_t wordsize, + const bool relies_on_same_type_inputs, + const std::set accepted_input_types) : + compliance_predicate_handler >(protoboard(), + type*100, + type, + max_arity, + relies_on_same_type_inputs, + accepted_input_types), + wordsize(wordsize) +{ + this->outgoing_message.reset(new tally_pcd_message_variable(this->pb, wordsize, "outgoing_message")); + this->arity.allocate(this->pb, "arity"); + + for (size_t i = 0; i < max_arity; ++i) + { + this->incoming_messages[i].reset(new tally_pcd_message_variable(this->pb, wordsize, FMT("", "incoming_messages_%zu", i))); + } + + this->local_data.reset(new tally_pcd_local_data_variable(this->pb, "local_data")); + + sum_out_packed.allocate(this->pb, "sum_out_packed"); + count_out_packed.allocate(this->pb, "count_out_packed"); + + sum_in_packed.allocate(this->pb, max_arity, "sum_in_packed"); + count_in_packed.allocate(this->pb, max_arity, "count_in_packed"); + + sum_in_packed_aux.allocate(this->pb, max_arity, "sum_in_packed_aux"); + count_in_packed_aux.allocate(this->pb, max_arity, "count_in_packed_aux"); + + type_val_inner_product.allocate(this->pb, "type_val_inner_product"); + for (auto &msg : this->incoming_messages) + { + incoming_types.emplace_back(msg->type); + } + + compute_type_val_inner_product.reset(new inner_product_gadget(this->pb, incoming_types, sum_in_packed, type_val_inner_product, "compute_type_val_inner_product")); + + unpack_sum_out.reset(new packing_gadget(this->pb, std::dynamic_pointer_cast >(this->outgoing_message)->sum_bits, sum_out_packed, "pack_sum_out")); + unpack_count_out.reset(new packing_gadget(this->pb, std::dynamic_pointer_cast >(this->outgoing_message)->count_bits, count_out_packed, "pack_count_out")); + + for (size_t i = 0; i < max_arity; ++i) + { + pack_sum_in.emplace_back(packing_gadget(this->pb, std::dynamic_pointer_cast >(this->incoming_messages[i])->sum_bits, sum_in_packed[i], FMT("", "pack_sum_in_%zu", i))); + pack_count_in.emplace_back(packing_gadget(this->pb, std::dynamic_pointer_cast >(this->incoming_messages[i])->sum_bits, count_in_packed[i], FMT("", "pack_count_in_%zu", i))); + } + + arity_indicators.allocate(this->pb, max_arity+1, "arity_indicators"); +} + +template +void tally_cp_handler::generate_r1cs_constraints() +{ + unpack_sum_out->generate_r1cs_constraints(true); + unpack_count_out->generate_r1cs_constraints(true); + + for (size_t i = 0; i < this->max_arity; ++i) + { + pack_sum_in[i].generate_r1cs_constraints(true); + pack_count_in[i].generate_r1cs_constraints(true); + } + + for (size_t i = 0; i < this->max_arity; ++i) + { + this->pb.add_r1cs_constraint(r1cs_constraint(incoming_types[i], sum_in_packed_aux[i], sum_in_packed[i]), FMT("", "initial_sum_%zu_is_zero", i)); + this->pb.add_r1cs_constraint(r1cs_constraint(incoming_types[i], count_in_packed_aux[i], count_in_packed[i]), FMT("", "initial_sum_%zu_is_zero", i)); + } + + /* constrain arity indicator variables so that arity_indicators[arity] = 1 and arity_indicators[i] = 0 for any other i */ + for (size_t i = 0; i < this->max_arity; ++i) + { + this->pb.add_r1cs_constraint(r1cs_constraint(this->arity - FieldT(i), arity_indicators[i], 0), FMT("", "arity_indicators_%zu", i)); + } + + this->pb.add_r1cs_constraint(r1cs_constraint(1, pb_sum(arity_indicators), 1), "arity_indicators"); + + /* require that types of messages that are past arity (i.e. unbound wires) carry 0 */ + for (size_t i = 0; i < this->max_arity; ++i) + { + this->pb.add_r1cs_constraint(r1cs_constraint(0 + pb_sum(pb_variable_array(arity_indicators.begin(), arity_indicators.begin() + i)), incoming_types[i], 0), FMT("", "unbound_types_%zu", i)); + } + + /* sum_out = local_data + \sum_i type[i] * sum_in[i] */ + compute_type_val_inner_product->generate_r1cs_constraints(); + this->pb.add_r1cs_constraint(r1cs_constraint(1, type_val_inner_product + std::dynamic_pointer_cast >(this->local_data)->summand, sum_out_packed), "update_sum"); + + /* count_out = 1 + \sum_i count_in[i] */ + this->pb.add_r1cs_constraint(r1cs_constraint(1, 1 + pb_sum(count_in_packed), count_out_packed), "update_count"); +} + +template +void tally_cp_handler::generate_r1cs_witness(const std::vector > > &incoming_messages, + const std::shared_ptr > &local_data) +{ + base_handler::generate_r1cs_witness(incoming_messages, local_data); + + for (size_t i = 0; i < this->max_arity; ++i) + { + pack_sum_in[i].generate_r1cs_witness_from_bits(); + pack_count_in[i].generate_r1cs_witness_from_bits(); + + if (!this->pb.val(incoming_types[i]).is_zero()) + { + this->pb.val(sum_in_packed_aux[i]) = this->pb.val(sum_in_packed[i]) * this->pb.val(incoming_types[i]).inverse(); + this->pb.val(count_in_packed_aux[i]) = this->pb.val(count_in_packed[i]) * this->pb.val(incoming_types[i]).inverse(); + } + } + + for (size_t i = 0; i < this->max_arity + 1; ++i) + { + this->pb.val(arity_indicators[i]) = (incoming_messages.size() == i ? FieldT::one() : FieldT::zero()); + } + + compute_type_val_inner_product->generate_r1cs_witness(); + this->pb.val(sum_out_packed) = this->pb.val(std::dynamic_pointer_cast >(this->local_data)->summand) + this->pb.val(type_val_inner_product); + + this->pb.val(count_out_packed) = FieldT::one(); + for (size_t i = 0; i < this->max_arity; ++i) + { + this->pb.val(count_out_packed) += this->pb.val(count_in_packed[i]); + } + + unpack_sum_out->generate_r1cs_witness_from_packed(); + unpack_count_out->generate_r1cs_witness_from_packed(); +} + +template +std::shared_ptr > tally_cp_handler::get_base_case_message() const +{ + const size_t type = 0; + const size_t sum = 0; + const size_t count = 0; + + std::shared_ptr > result; + result.reset(new tally_pcd_message(type, wordsize, sum, count)); + + return result; +} + +} // libsnark + +#endif // TALLY_CP_TCC_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/pcd/r1cs_pcd/ppzkpcd_compliance_predicate.hpp b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/pcd/r1cs_pcd/ppzkpcd_compliance_predicate.hpp new file mode 100644 index 0000000..b605b83 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/pcd/r1cs_pcd/ppzkpcd_compliance_predicate.hpp @@ -0,0 +1,37 @@ +/** @file + ***************************************************************************** + + Template aliasing for prettifying R1CS PCD interfaces. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef PPZKPCD_COMPLIANCE_PREDICATE_HPP_ +#define PPZKPCD_COMPLIANCE_PREDICATE_HPP_ + +#include "algebra/curves/public_params.hpp" +#include "zk_proof_systems/pcd/r1cs_pcd/compliance_predicate/compliance_predicate.hpp" + +namespace libsnark { + +/* template aliasing for R1CS (multi-predicate) ppzkPCD: */ + +template +using r1cs_mp_ppzkpcd_compliance_predicate = r1cs_pcd_compliance_predicate >; + +template +using r1cs_mp_ppzkpcd_message = r1cs_pcd_message >; + +template +using r1cs_mp_ppzkpcd_local_data = r1cs_pcd_local_data >; + +template +using r1cs_mp_ppzkpcd_variable_assignment = r1cs_variable_assignment >; + +} + +#endif // PPZKPCD_COMPLIANCE_PREDICATE_HPP_ + diff --git a/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/pcd/r1cs_pcd/r1cs_mp_ppzkpcd/examples/run_r1cs_mp_ppzkpcd.hpp b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/pcd/r1cs_pcd/r1cs_mp_ppzkpcd/examples/run_r1cs_mp_ppzkpcd.hpp new file mode 100644 index 0000000..961bdd7 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/pcd/r1cs_pcd/r1cs_mp_ppzkpcd/examples/run_r1cs_mp_ppzkpcd.hpp @@ -0,0 +1,39 @@ +/** @file + ***************************************************************************** + + Declaration of functionality that runs the R1CS multi-predicate ppzkPCD + for a compliance predicate example. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef RUN_R1CS_MP_PPZKPCD_HPP_ +#define RUN_R1CS_MP_PPZKPCD_HPP_ + +namespace libsnark { + +/** + * Runs the multi-predicate ppzkPCD (generator, prover, and verifier) for the + * "tally compliance predicate", of a given wordsize, arity, and depth. + * + * Optionally, also test the serialization routines for keys and proofs. + * (This takes additional time.) + * + * Optionally, also test the case of compliance predicates with different types. + */ +template +bool run_r1cs_mp_ppzkpcd_tally_example(const size_t wordsize, + const size_t max_arity, + const size_t depth, + const bool test_serialization, + const bool test_multi_type, + const bool test_same_type_optimization); + +} // libsnark + +#include "zk_proof_systems/pcd/r1cs_pcd/r1cs_mp_ppzkpcd/examples/run_r1cs_mp_ppzkpcd.tcc" + +#endif // RUN_R1CS_MP_PPZKPCD_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/pcd/r1cs_pcd/r1cs_mp_ppzkpcd/examples/run_r1cs_mp_ppzkpcd.tcc b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/pcd/r1cs_pcd/r1cs_mp_ppzkpcd/examples/run_r1cs_mp_ppzkpcd.tcc new file mode 100644 index 0000000..7645273 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/pcd/r1cs_pcd/r1cs_mp_ppzkpcd/examples/run_r1cs_mp_ppzkpcd.tcc @@ -0,0 +1,206 @@ +/** @file + ***************************************************************************** + + Implementation of functionality that runs the R1CS multi-predicate ppzkPCD + for a compliance predicate example. + + See run_r1cs_mp_ppzkpcd.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef RUN_R1CS_MP_PPZKPCD_TCC_ +#define RUN_R1CS_MP_PPZKPCD_TCC_ + +#include "zk_proof_systems/pcd/r1cs_pcd/r1cs_mp_ppzkpcd/r1cs_mp_ppzkpcd.hpp" + +#include "zk_proof_systems/pcd/r1cs_pcd/compliance_predicate/examples/tally_cp.hpp" + +namespace libsnark { + +template +bool run_r1cs_mp_ppzkpcd_tally_example(const size_t wordsize, + const size_t max_arity, + const size_t depth, + const bool test_serialization, + const bool test_multi_type, + const bool test_same_type_optimization) +{ + enter_block("Call to run_r1cs_mp_ppzkpcd_tally_example"); + + typedef Fr FieldT; + + bool all_accept = true; + + enter_block("Generate all messages"); + size_t tree_size = 0; + size_t nodes_in_layer = 1; + for (size_t layer = 0; layer <= depth; ++layer) + { + tree_size += nodes_in_layer; + nodes_in_layer *= max_arity; + } + + std::vector tree_types(tree_size); + std::vector tree_elems(tree_size); + std::vector tree_arity(tree_size); + + nodes_in_layer = 1; + size_t node_idx = 0; + for (size_t layer = 0; layer <= depth; ++layer) + { + for (size_t id_in_layer = 0; id_in_layer < nodes_in_layer; ++id_in_layer, ++node_idx) + { + if (!test_multi_type) + { + tree_types[node_idx] = 1; + } + else + { + if (test_same_type_optimization) + { + tree_types[node_idx] = 1 + ((depth-layer) & 1); + } + else + { + tree_types[node_idx] = 1 + (std::rand() % 2); + } + } + + tree_elems[node_idx] = std::rand() % 100; + tree_arity[node_idx] = 1 + (std::rand() % max_arity); /* we will just skip below this threshold */ + printf("tree_types[%zu] = %zu\n", node_idx, tree_types[node_idx]); + printf("tree_elems[%zu] = %zu\n", node_idx, tree_elems[node_idx]); + printf("tree_arity[%zu] = %zu\n", node_idx, tree_arity[node_idx]); + + } + nodes_in_layer *= max_arity; + } + + leave_block("Generate all messages"); + + std::vector > tree_proofs(tree_size); + std::vector > > tree_messages(tree_size); + + enter_block("Generate compliance predicates"); + std::set tally_1_accepted_types, tally_2_accepted_types; + if (test_same_type_optimization) + { + if (!test_multi_type) + { + /* only tally 1 is going to be used */ + tally_1_accepted_types.insert(1); + } + else + { + tally_1_accepted_types.insert(2); + tally_2_accepted_types.insert(1); + } + } + + tally_cp_handler tally_1(1, max_arity, wordsize, test_same_type_optimization, tally_1_accepted_types); + tally_cp_handler tally_2(2, max_arity, wordsize, test_same_type_optimization, tally_2_accepted_types); + tally_1.generate_r1cs_constraints(); + tally_2.generate_r1cs_constraints(); + r1cs_pcd_compliance_predicate cp_1 = tally_1.get_compliance_predicate(); + r1cs_pcd_compliance_predicate cp_2 = tally_2.get_compliance_predicate(); + leave_block("Generate compliance predicates"); + + print_header("R1CS ppzkPCD Generator"); + r1cs_mp_ppzkpcd_keypair keypair = r1cs_mp_ppzkpcd_generator({ cp_1, cp_2 }); + + print_header("Process verification key"); + r1cs_mp_ppzkpcd_processed_verification_key pvk = r1cs_mp_ppzkpcd_process_vk(keypair.vk); + + if (test_serialization) + { + enter_block("Test serialization of keys"); + keypair.pk = reserialize >(keypair.pk); + keypair.vk = reserialize >(keypair.vk); + pvk = reserialize >(pvk); + leave_block("Test serialization of keys"); + } + + std::shared_ptr > base_msg = tally_1.get_base_case_message(); /* we choose the base to always be tally_1 */ + nodes_in_layer /= max_arity; + for (long layer = depth; layer >= 0; --layer, nodes_in_layer /= max_arity) + { + for (size_t i = 0; i < nodes_in_layer; ++i) + { + const size_t cur_idx = (nodes_in_layer - 1) / (max_arity - 1) + i; + + tally_cp_handler &cur_tally = (tree_types[cur_idx] == 1 ? tally_1 : tally_2); + r1cs_pcd_compliance_predicate &cur_cp = (tree_types[cur_idx] == 1 ? cp_1 : cp_2); + + const bool base_case = (max_arity * cur_idx + max_arity >= tree_size); + + std::vector > > msgs(max_arity, base_msg); + std::vector > proofs(max_arity); + + if (!base_case) + { + for (size_t i = 0; i < max_arity; ++i) + { + msgs[i] = tree_messages[max_arity*cur_idx + i + 1]; + proofs[i] = tree_proofs[max_arity*cur_idx + i + 1]; + } + } + msgs.resize(tree_arity[i]); + proofs.resize(tree_arity[i]); + + std::shared_ptr > ld; + ld.reset(new tally_pcd_local_data(tree_elems[cur_idx])); + cur_tally.generate_r1cs_witness(msgs, ld); + + const r1cs_pcd_compliance_predicate_primary_input tally_primary_input(cur_tally.get_outgoing_message()); + const r1cs_pcd_compliance_predicate_auxiliary_input tally_auxiliary_input(msgs, ld, cur_tally.get_witness()); + + print_header("R1CS ppzkPCD Prover"); + r1cs_mp_ppzkpcd_proof proof = r1cs_mp_ppzkpcd_prover(keypair.pk, cur_cp.name, tally_primary_input, tally_auxiliary_input, proofs); + + if (test_serialization) + { + enter_block("Test serialization of proof"); + proof = reserialize >(proof); + leave_block("Test serialization of proof"); + } + + tree_proofs[cur_idx] = proof; + tree_messages[cur_idx] = cur_tally.get_outgoing_message(); + + print_header("R1CS ppzkPCD Verifier"); + const r1cs_mp_ppzkpcd_primary_input pcd_verifier_input(tree_messages[cur_idx]); + const bool ans = r1cs_mp_ppzkpcd_verifier(keypair.vk, pcd_verifier_input, tree_proofs[cur_idx]); + + print_header("R1CS ppzkPCD Online Verifier"); + const bool ans2 = r1cs_mp_ppzkpcd_online_verifier(pvk, pcd_verifier_input, tree_proofs[cur_idx]); + assert(ans == ans2); + + all_accept = all_accept && ans; + + printf("\n"); + for (size_t i = 0; i < msgs.size(); ++i) + { + printf("Message %zu was:\n", i); + msgs[i]->print(); + } + printf("Summand at this node:\n%zu\n", tree_elems[cur_idx]); + printf("Outgoing message is:\n"); + tree_messages[cur_idx]->print(); + printf("\n"); + printf("Current node = %zu. Current proof verifies = %s\n", cur_idx, ans ? "YES" : "NO"); + printf("\n\n\n ================================================================================\n\n\n"); + } + } + + leave_block("Call to run_r1cs_mp_ppzkpcd_tally_example"); + + return all_accept; +} + +} // libsnark + +#endif // RUN_R1CS_MP_PPZKPCD_TCC_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/pcd/r1cs_pcd/r1cs_mp_ppzkpcd/mp_pcd_circuits.hpp b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/pcd/r1cs_pcd/r1cs_mp_ppzkpcd/mp_pcd_circuits.hpp new file mode 100644 index 0000000..7981056 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/pcd/r1cs_pcd/r1cs_mp_ppzkpcd/mp_pcd_circuits.hpp @@ -0,0 +1,183 @@ +/** @file + ***************************************************************************** + + Declaration of functionality for creating and using the two PCD circuits in + a multi-predicate PCD construction. + + The implementation follows, extends, and optimizes the approach described + in \[CTV15]. At high level, there is a "compliance step" circuit and a + "translation step" circuit, for each compliance predicate. For more details, + see \[CTV15]. + + + References: + + \[CTV15]: + "Cluster Computing in Zero Knowledge", + Alessandro Chiesa, Eran Tromer, Madars Virza + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef MP_PCD_CIRCUITS_HPP_ +#define MP_PCD_CIRCUITS_HPP_ + +#include "gadgetlib1/gadget.hpp" +#include "gadgetlib1/gadgets/gadget_from_r1cs.hpp" +#include "gadgetlib1/gadgets/hashes/crh_gadget.hpp" +#include "gadgetlib1/gadgets/set_commitment/set_commitment_gadget.hpp" +#include "gadgetlib1/gadgets/verifiers/r1cs_ppzksnark_verifier_gadget.hpp" +#include "zk_proof_systems/pcd/r1cs_pcd/compliance_predicate/cp_handler.hpp" + +namespace libsnark { + +/**************************** Compliance step ********************************/ + +/** + * A compliance-step PCD circuit. + * + * The circuit is an R1CS that checks compliance (for the given compliance predicate) + * and validity of previous proofs. + */ +template +class mp_compliance_step_pcd_circuit_maker { +public: + typedef Fr FieldT; + + r1cs_pcd_compliance_predicate compliance_predicate; + + protoboard pb; + + pb_variable zero; + + std::shared_ptr > block_for_outgoing_message; + std::shared_ptr > hash_outgoing_message; + + std::vector > block_for_incoming_messages; + std::vector > commitment_and_incoming_message_digests; + std::vector > unpack_commitment_and_incoming_message_digests; + std::vector > commitment_and_incoming_messages_digest_bits; + std::vector > hash_incoming_messages; + + std::vector > translation_step_vks; + std::vector > translation_step_vks_bits; + + pb_variable outgoing_message_type; + pb_variable_array outgoing_message_payload; + pb_variable_array outgoing_message_vars; + + pb_variable arity; + std::vector > incoming_message_types; + std::vector > incoming_message_payloads; + std::vector > incoming_message_vars; + + pb_variable_array local_data; + pb_variable_array cp_witness; + std::shared_ptr > compliance_predicate_as_gadget; + + pb_variable_array outgoing_message_bits; + std::shared_ptr > unpack_outgoing_message; + + std::vector > incoming_messages_bits; + std::vector > unpack_incoming_messages; + + pb_variable_array mp_compliance_step_pcd_circuit_input; + pb_variable_array padded_translation_step_vk_and_outgoing_message_digest; + std::vector > padded_commitment_and_incoming_messages_digest; + + std::shared_ptr > > commitment; + std::vector > > membership_proofs; + std::vector > > membership_checkers; + pb_variable_array membership_check_results; + pb_variable common_type; + pb_variable_array common_type_check_aux; + + std::vector > verifier_input; + std::vector > proof; + pb_variable_array verification_results; + std::vector > verifier; + + mp_compliance_step_pcd_circuit_maker(const r1cs_pcd_compliance_predicate &compliance_predicate, + const size_t max_number_of_predicates); + void generate_r1cs_constraints(); + r1cs_constraint_system get_circuit() const; + + void generate_r1cs_witness(const set_commitment &commitment_to_translation_step_r1cs_vks, + const std::vector > > &mp_translation_step_pcd_circuit_vks, + const std::vector &vk_membership_proofs, + const r1cs_pcd_compliance_predicate_primary_input &compliance_predicate_primary_input, + const r1cs_pcd_compliance_predicate_auxiliary_input &compliance_predicate_auxiliary_input, + const std::vector > > &translation_step_proofs); + r1cs_primary_input get_primary_input() const; + r1cs_auxiliary_input get_auxiliary_input() const; + + static size_t field_logsize(); + static size_t field_capacity(); + static size_t input_size_in_elts(); + static size_t input_capacity_in_bits(); + static size_t input_size_in_bits(); +}; + +/*************************** Translation step ********************************/ + +/** + * A translation-step PCD circuit. + * + * The circuit is an R1CS that checks validity of previous proofs. + */ +template +class mp_translation_step_pcd_circuit_maker { +public: + typedef Fr FieldT; + + protoboard pb; + + pb_variable_array mp_translation_step_pcd_circuit_input; + pb_variable_array unpacked_mp_translation_step_pcd_circuit_input; + pb_variable_array verifier_input; + std::shared_ptr > unpack_mp_translation_step_pcd_circuit_input; + + std::shared_ptr > hardcoded_compliance_step_vk; + std::shared_ptr > proof; + std::shared_ptr > online_verifier; + + mp_translation_step_pcd_circuit_maker(const r1cs_ppzksnark_verification_key > &compliance_step_vk); + void generate_r1cs_constraints(); + r1cs_constraint_system get_circuit() const; + + void generate_r1cs_witness(const r1cs_primary_input > translation_step_input, + const r1cs_ppzksnark_proof > &prev_proof); + r1cs_primary_input get_primary_input() const; + r1cs_auxiliary_input get_auxiliary_input() const; + + static size_t field_logsize(); + static size_t field_capacity(); + static size_t input_size_in_elts(); + static size_t input_capacity_in_bits(); + static size_t input_size_in_bits(); +}; + +/****************************** Input maps ***********************************/ + +/** + * Obtain the primary input for a compliance-step PCD circuit. + */ +template +r1cs_primary_input > get_mp_compliance_step_pcd_circuit_input(const set_commitment &commitment_to_translation_step_r1cs_vks, + const r1cs_pcd_compliance_predicate_primary_input > &primary_input); + +/** + * Obtain the primary input for a translation-step PCD circuit. + */ +template +r1cs_primary_input > get_mp_translation_step_pcd_circuit_input(const set_commitment &commitment_to_translation_step_r1cs_vks, + const r1cs_pcd_compliance_predicate_primary_input > > &primary_input); + +} // libsnark + +#include "zk_proof_systems/pcd/r1cs_pcd/r1cs_mp_ppzkpcd/mp_pcd_circuits.tcc" + +#endif // MP_PCD_CIRCUITS_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/pcd/r1cs_pcd/r1cs_mp_ppzkpcd/mp_pcd_circuits.tcc b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/pcd/r1cs_pcd/r1cs_mp_ppzkpcd/mp_pcd_circuits.tcc new file mode 100644 index 0000000..713225d --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/pcd/r1cs_pcd/r1cs_mp_ppzkpcd/mp_pcd_circuits.tcc @@ -0,0 +1,679 @@ +/** @file + ***************************************************************************** + + Implementation of functionality for creating and using the two PCD circuits in + a multi-predicate PCD construction. + + See mp_pcd_circuits.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef MP_PCD_CIRCUITS_TCC_ +#define MP_PCD_CIRCUITS_TCC_ + +#include +#include "common/utils.hpp" +#include "gadgetlib1/constraint_profiling.hpp" + +namespace libsnark { + +template +mp_compliance_step_pcd_circuit_maker::mp_compliance_step_pcd_circuit_maker(const r1cs_pcd_compliance_predicate &compliance_predicate, + const size_t max_number_of_predicates) : + compliance_predicate(compliance_predicate) +{ + /* calculate some useful sizes */ + const size_t digest_size = CRH_with_field_out_gadget::get_digest_len(); + const size_t outgoing_msg_size_in_bits = field_logsize() * (1 + compliance_predicate.outgoing_message_payload_length); + assert(compliance_predicate.has_equal_input_lengths()); + const size_t translation_step_vk_size_in_bits = r1cs_ppzksnark_verification_key_variable::size_in_bits(mp_translation_step_pcd_circuit_maker >::input_size_in_elts()); + const size_t padded_verifier_input_size = mp_translation_step_pcd_circuit_maker >::input_capacity_in_bits(); + const size_t commitment_size = set_commitment_gadget >::root_size_in_bits(); + + const size_t output_block_size = commitment_size + outgoing_msg_size_in_bits; + const size_t max_incoming_payload_length = *std::max_element(compliance_predicate.incoming_message_payload_lengths.begin(), compliance_predicate.incoming_message_payload_lengths.end()); + const size_t max_input_block_size = commitment_size + field_logsize() * (1 + max_incoming_payload_length); + + CRH_with_bit_out_gadget::sample_randomness(std::max(output_block_size, max_input_block_size)); + + /* allocate input of the compliance MP_PCD circuit */ + mp_compliance_step_pcd_circuit_input.allocate(pb, input_size_in_elts(), "mp_compliance_step_pcd_circuit_input"); + + /* allocate inputs to the compliance predicate */ + outgoing_message_type.allocate(pb, "outgoing_message_type"); + outgoing_message_payload.allocate(pb, compliance_predicate.outgoing_message_payload_length, "outgoing_message_payload"); + + outgoing_message_vars.insert(outgoing_message_vars.end(), outgoing_message_type); + outgoing_message_vars.insert(outgoing_message_vars.end(), outgoing_message_payload.begin(), outgoing_message_payload.end()); + + arity.allocate(pb, "arity"); + + incoming_message_types.resize(compliance_predicate.max_arity); + incoming_message_payloads.resize(compliance_predicate.max_arity); + incoming_message_vars.resize(compliance_predicate.max_arity); + for (size_t i = 0; i < compliance_predicate.max_arity; ++i) + { + incoming_message_types[i].allocate(pb, FMT("", "incoming_message_type_%zu", i)); + incoming_message_payloads[i].allocate(pb, compliance_predicate.incoming_message_payload_lengths[i], FMT("", "incoming_message_payloads_%zu", i)); + + incoming_message_vars[i].insert(incoming_message_vars[i].end(), incoming_message_types[i]); + incoming_message_vars[i].insert(incoming_message_vars[i].end(), incoming_message_payloads[i].begin(), incoming_message_payloads[i].end()); + } + + local_data.allocate(pb, compliance_predicate.local_data_length, "local_data"); + cp_witness.allocate(pb, compliance_predicate.witness_length, "cp_witness"); + + /* convert compliance predicate from a constraint system into a gadget */ + pb_variable_array incoming_messages_concat; + for (size_t i = 0; i < compliance_predicate.max_arity; ++i) + { + incoming_messages_concat.insert(incoming_messages_concat.end(), incoming_message_vars[i].begin(), incoming_message_vars[i].end()); + } + + compliance_predicate_as_gadget.reset(new gadget_from_r1cs(pb, + { outgoing_message_vars, + pb_variable_array(1, arity), + incoming_messages_concat, + local_data, + cp_witness }, + compliance_predicate.constraint_system, "compliance_predicate_as_gadget")); + + /* unpack messages to bits */ + outgoing_message_bits.allocate(pb, outgoing_msg_size_in_bits, "outgoing_message_bits"); + unpack_outgoing_message.reset(new multipacking_gadget(pb, outgoing_message_bits, outgoing_message_vars, field_logsize(), "unpack_outgoing_message")); + + incoming_messages_bits.resize(compliance_predicate.max_arity); + for (size_t i = 0; i < compliance_predicate.max_arity; ++i) + { + const size_t incoming_msg_size_in_bits = field_logsize() * (1 + compliance_predicate.incoming_message_payload_lengths[i]); + + incoming_messages_bits[i].allocate(pb, incoming_msg_size_in_bits, FMT("", "incoming_messages_bits_%zu", i)); + unpack_incoming_messages.emplace_back(multipacking_gadget(pb, incoming_messages_bits[i], incoming_message_vars[i], field_logsize(), FMT("", "unpack_incoming_messages_%zu", i))); + } + + /* allocate digests */ + commitment_and_incoming_message_digests.resize(compliance_predicate.max_arity); + for (size_t i = 0; i < compliance_predicate.max_arity; ++i) + { + commitment_and_incoming_message_digests[i].allocate(pb, digest_size, FMT("", "commitment_and_incoming_message_digests_%zu", i)); + } + + /* allocate commitment, verification key(s) and membership checker(s)/proof(s) */ + commitment.reset(new set_commitment_variable >(pb, commitment_size, "commitment")); + + print_indent(); printf("* %s perform same type optimization for compliance predicate with type %zu\n", + (compliance_predicate.relies_on_same_type_inputs ? "Will" : "Will NOT"), + compliance_predicate.type); + if (compliance_predicate.relies_on_same_type_inputs) + { + /* only one set_commitment_gadget is needed */ + common_type.allocate(pb, "common_type"); + common_type_check_aux.allocate(pb, compliance_predicate.accepted_input_types.size(), "common_type_check_aux"); + + translation_step_vks_bits.resize(1); + translation_step_vks_bits[0].allocate(pb, translation_step_vk_size_in_bits, "translation_step_vk_bits"); + membership_check_results.allocate(pb, 1, "membership_check_results"); + + membership_proofs.emplace_back(set_membership_proof_variable>(pb, + max_number_of_predicates, + "membership_proof")); + membership_checkers.emplace_back(set_commitment_gadget>(pb, + max_number_of_predicates, + translation_step_vks_bits[0], + *commitment, + membership_proofs[0], + membership_check_results[0], "membership_checker")); + } + else + { + /* check for max_arity possibly different VKs */ + translation_step_vks_bits.resize(compliance_predicate.max_arity); + membership_check_results.allocate(pb, compliance_predicate.max_arity, "membership_check_results"); + + for (size_t i = 0; i < compliance_predicate.max_arity; ++i) + { + translation_step_vks_bits[i].allocate(pb, translation_step_vk_size_in_bits, FMT("", "translation_step_vks_bits_%zu", i)); + + membership_proofs.emplace_back(set_membership_proof_variable >(pb, + max_number_of_predicates, + FMT("", "membership_proof_%zu", i))); + membership_checkers.emplace_back(set_commitment_gadget >(pb, + max_number_of_predicates, + translation_step_vks_bits[i], + *commitment, + membership_proofs[i], + membership_check_results[i], + FMT("", "membership_checkers_%zu", i))); + } + } + + /* allocate blocks */ + block_for_outgoing_message.reset(new block_variable(pb, { commitment->bits, outgoing_message_bits }, "block_for_outgoing_message")); + + for (size_t i = 0; i < compliance_predicate.max_arity; ++i) + { + block_for_incoming_messages.emplace_back(block_variable(pb, { commitment->bits, incoming_messages_bits[i] }, FMT("", "block_for_incoming_messages_%zu", i))); + } + + /* allocate hash checkers */ + hash_outgoing_message.reset(new CRH_with_field_out_gadget(pb, output_block_size, *block_for_outgoing_message, mp_compliance_step_pcd_circuit_input, "hash_outgoing_message")); + + for (size_t i = 0; i < compliance_predicate.max_arity; ++i) + { + const size_t input_block_size = commitment_size + incoming_messages_bits[i].size(); + hash_incoming_messages.emplace_back(CRH_with_field_out_gadget(pb, input_block_size, block_for_incoming_messages[i], commitment_and_incoming_message_digests[i], FMT("", "hash_incoming_messages_%zu", i))); + } + + /* allocate useful zero variable */ + zero.allocate(pb, "zero"); + + /* prepare arguments for the verifier */ + if (compliance_predicate.relies_on_same_type_inputs) + { + translation_step_vks.emplace_back(r1cs_ppzksnark_verification_key_variable(pb, translation_step_vks_bits[0], mp_translation_step_pcd_circuit_maker >::input_size_in_elts(), "translation_step_vk")); + } + else + { + for (size_t i = 0; i < compliance_predicate.max_arity; ++i) + { + translation_step_vks.emplace_back(r1cs_ppzksnark_verification_key_variable(pb, translation_step_vks_bits[i], mp_translation_step_pcd_circuit_maker >::input_size_in_elts(), FMT("", "translation_step_vks_%zu", i))); + } + } + + verification_results.allocate(pb, compliance_predicate.max_arity, "verification_results"); + commitment_and_incoming_messages_digest_bits.resize(compliance_predicate.max_arity); + + for (size_t i = 0; i < compliance_predicate.max_arity; ++i) + { + commitment_and_incoming_messages_digest_bits[i].allocate(pb, digest_size * field_logsize(), FMT("", "commitment_and_incoming_messages_digest_bits_%zu", i)); + unpack_commitment_and_incoming_message_digests.emplace_back(multipacking_gadget(pb, + commitment_and_incoming_messages_digest_bits[i], + commitment_and_incoming_message_digests[i], + field_logsize(), + FMT("", "unpack_commitment_and_incoming_message_digests_%zu", i))); + + verifier_input.emplace_back(commitment_and_incoming_messages_digest_bits[i]); + while (verifier_input[i].size() < padded_verifier_input_size) + { + verifier_input[i].emplace_back(zero); + } + + proof.emplace_back(r1cs_ppzksnark_proof_variable(pb, FMT("", "proof_%zu", i))); + const r1cs_ppzksnark_verification_key_variable &vk_to_be_used = (compliance_predicate.relies_on_same_type_inputs ? translation_step_vks[0] : translation_step_vks[i]); + verifier.emplace_back(r1cs_ppzksnark_verifier_gadget(pb, + vk_to_be_used, + verifier_input[i], + mp_translation_step_pcd_circuit_maker >::field_capacity(), + proof[i], + verification_results[i], + FMT("", "verifier_%zu", i))); + } + + pb.set_input_sizes(input_size_in_elts()); +} + +template +void mp_compliance_step_pcd_circuit_maker::generate_r1cs_constraints() +{ + const size_t digest_size = CRH_with_bit_out_gadget::get_digest_len(); + const size_t dimension = knapsack_dimension::dimension; + print_indent(); printf("* Knapsack dimension: %zu\n", dimension); + + print_indent(); printf("* Compliance predicate arity: %zu\n", compliance_predicate.max_arity); + print_indent(); printf("* Compliance predicate outgoing payload length: %zu\n", compliance_predicate.outgoing_message_payload_length); + print_indent(); printf("* Compliance predicate inncoming payload lengts:"); + for (auto l : compliance_predicate.incoming_message_payload_lengths) + { + printf(" %zu", l); + } + printf("\n"); + print_indent(); printf("* Compliance predicate local data length: %zu\n", compliance_predicate.local_data_length); + print_indent(); printf("* Compliance predicate witness length: %zu\n", compliance_predicate.witness_length); + + PROFILE_CONSTRAINTS(pb, "booleanity") + { + PROFILE_CONSTRAINTS(pb, "booleanity: unpack outgoing_message") + { + unpack_outgoing_message->generate_r1cs_constraints(true); + } + + PROFILE_CONSTRAINTS(pb, "booleanity: unpack s incoming_messages") + { + for (size_t i = 0; i < compliance_predicate.max_arity; ++i) + { + unpack_incoming_messages[i].generate_r1cs_constraints(true); + } + } + + PROFILE_CONSTRAINTS(pb, "booleanity: unpack verification key") + { + for (size_t i = 0; i < translation_step_vks.size(); ++i) + { + translation_step_vks[i].generate_r1cs_constraints(true); + } + } + } + + PROFILE_CONSTRAINTS(pb, "(1+s) copies of hash") + { + print_indent(); printf("* Digest-size: %zu\n", digest_size); + hash_outgoing_message->generate_r1cs_constraints(); + + for (size_t i = 0; i < compliance_predicate.max_arity; ++i) + { + hash_incoming_messages[i].generate_r1cs_constraints(); + } + } + + PROFILE_CONSTRAINTS(pb, "s copies of repacking circuit for verifier") + { + for (size_t i = 0; i < compliance_predicate.max_arity; ++i) + { + unpack_commitment_and_incoming_message_digests[i].generate_r1cs_constraints(true); + } + } + + PROFILE_CONSTRAINTS(pb, "set membership check") + { + for (auto &membership_proof : membership_proofs) + { + membership_proof.generate_r1cs_constraints(); + } + + for (auto &membership_checker : membership_checkers) + { + membership_checker.generate_r1cs_constraints(); + } + } + + PROFILE_CONSTRAINTS(pb, "compliance predicate") + { + compliance_predicate_as_gadget->generate_r1cs_constraints(); + } + + PROFILE_CONSTRAINTS(pb, "s copies of verifier for translated proofs") + { + PROFILE_CONSTRAINTS(pb, "check that s proofs lie on the curve") + { + for (size_t i = 0; i < compliance_predicate.max_arity; ++i) + { + proof[i].generate_r1cs_constraints(); + } + } + + for (size_t i = 0; i < compliance_predicate.max_arity; ++i) + { + verifier[i].generate_r1cs_constraints(); + } + } + + PROFILE_CONSTRAINTS(pb, "miscellaneous") + { + generate_r1cs_equals_const_constraint(pb, zero, FieldT::zero(), "zero"); + + PROFILE_CONSTRAINTS(pb, "check that s proofs lie on the curve") + { + for (size_t i = 0; i < compliance_predicate.max_arity; ++i) + { + generate_boolean_r1cs_constraint(pb, verification_results[i], FMT("", "verification_results_%zu", i)); + } + } + + /* either type = 0 or proof verified w.r.t. a valid verification key */ + PROFILE_CONSTRAINTS(pb, "check that s messages have valid proofs (or are base case)") + { + for (size_t i = 0; i < compliance_predicate.max_arity; ++i) + { + pb.add_r1cs_constraint(r1cs_constraint(incoming_message_types[i], 1 - verification_results[i], 0), FMT("", "not_base_case_implies_valid_proof_%zu", i)); + } + } + + if (compliance_predicate.relies_on_same_type_inputs) + { + PROFILE_CONSTRAINTS(pb, "check that all non-base case messages are of same type and that VK is validly selected") + { + for (size_t i = 0; i < compliance_predicate.max_arity; ++i) + { + pb.add_r1cs_constraint(r1cs_constraint(incoming_message_types[i], incoming_message_types[i] - common_type, 0), FMT("", "non_base_types_equal_%zu", i)); + } + + pb.add_r1cs_constraint(r1cs_constraint(common_type, 1 - membership_check_results[0], 0), "valid_vk_for_the_common_type"); + + auto it = compliance_predicate.accepted_input_types.begin(); + for (size_t i = 0; i < compliance_predicate.accepted_input_types.size(); ++i, ++it) + { + pb.add_r1cs_constraint(r1cs_constraint((i == 0 ? common_type : common_type_check_aux[i-1]), + common_type - FieldT(*it), + (i == compliance_predicate.accepted_input_types.size() - 1 ? 0 * ONE : common_type_check_aux[i])), + FMT("", "common_type_in_prescribed_set_%zu_must_equal_%zu", i, *it)); + } + } + } + else + { + PROFILE_CONSTRAINTS(pb, "check that all s messages have validly selected VKs") + { + for (size_t i = 0; i < compliance_predicate.max_arity; ++i) + { + pb.add_r1cs_constraint(r1cs_constraint(incoming_message_types[i], 1 - membership_check_results[i], 0), FMT("", "not_base_case_implies_valid_vk_%zu", i)); + } + } + } + pb.add_r1cs_constraint(r1cs_constraint(1, outgoing_message_type, FieldT(compliance_predicate.type)), "enforce_outgoing_type"); + } + + PRINT_CONSTRAINT_PROFILING(); + print_indent(); printf("* Number of constraints in mp_compliance_step_pcd_circuit: %zu\n", pb.num_constraints()); +} + +template +r1cs_constraint_system > mp_compliance_step_pcd_circuit_maker::get_circuit() const +{ + return pb.get_constraint_system(); +} + +template +r1cs_primary_input > mp_compliance_step_pcd_circuit_maker::get_primary_input() const +{ + return pb.primary_input(); +} + +template +r1cs_auxiliary_input > mp_compliance_step_pcd_circuit_maker::get_auxiliary_input() const +{ + return pb.auxiliary_input(); +} + +template +void mp_compliance_step_pcd_circuit_maker::generate_r1cs_witness(const set_commitment &commitment_to_translation_step_r1cs_vks, + const std::vector > > &mp_translation_step_pcd_circuit_vks, + const std::vector &vk_membership_proofs, + const r1cs_pcd_compliance_predicate_primary_input &compliance_predicate_primary_input, + const r1cs_pcd_compliance_predicate_auxiliary_input &compliance_predicate_auxiliary_input, + const std::vector > > &translation_step_proofs) +{ + this->pb.clear_values(); + this->pb.val(zero) = FieldT::zero(); + + compliance_predicate_as_gadget->generate_r1cs_witness(compliance_predicate_primary_input.as_r1cs_primary_input(), + compliance_predicate_auxiliary_input.as_r1cs_auxiliary_input(compliance_predicate.incoming_message_payload_lengths)); + + unpack_outgoing_message->generate_r1cs_witness_from_packed(); + for (size_t i = 0; i < compliance_predicate.max_arity; ++i) + { + unpack_incoming_messages[i].generate_r1cs_witness_from_packed(); + } + + for (size_t i = 0; i < translation_step_vks.size(); ++i) + { + translation_step_vks[i].generate_r1cs_witness(mp_translation_step_pcd_circuit_vks[i]); + } + + commitment->generate_r1cs_witness(commitment_to_translation_step_r1cs_vks); + + if (compliance_predicate.relies_on_same_type_inputs) + { + /* all messages (except base case) must be of the same type */ + this->pb.val(common_type) = FieldT::zero(); + size_t nonzero_type_idx = 0; + for (size_t i = 0; i < compliance_predicate.max_arity; ++i) + { + if (this->pb.val(incoming_message_types[i]) == 0) + { + continue; + } + + if (this->pb.val(common_type).is_zero()) + { + this->pb.val(common_type) = this->pb.val(incoming_message_types[i]); + nonzero_type_idx = i; + } + else + { + assert(this->pb.val(common_type) == this->pb.val(incoming_message_types[i])); + } + } + + this->pb.val(membership_check_results[0]) = (this->pb.val(common_type).is_zero() ? FieldT::zero() : FieldT::one()); + membership_proofs[0].generate_r1cs_witness(vk_membership_proofs[nonzero_type_idx]); + membership_checkers[0].generate_r1cs_witness(); + + auto it = compliance_predicate.accepted_input_types.begin(); + for (size_t i = 0; i < compliance_predicate.accepted_input_types.size(); ++i, ++it) + { + pb.val(common_type_check_aux[i]) = ((i == 0 ? pb.val(common_type) : pb.val(common_type_check_aux[i-1])) * + (pb.val(common_type) - FieldT(*it))); + } + } + else + { + for (size_t i = 0; i < membership_checkers.size(); ++i) + { + this->pb.val(membership_check_results[i]) = (this->pb.val(incoming_message_types[i]).is_zero() ? FieldT::zero() : FieldT::one()); + membership_proofs[i].generate_r1cs_witness(vk_membership_proofs[i]); + membership_checkers[i].generate_r1cs_witness(); + } + } + + hash_outgoing_message->generate_r1cs_witness(); + for (size_t i = 0; i < compliance_predicate.max_arity; ++i) + { + hash_incoming_messages[i].generate_r1cs_witness(); + unpack_commitment_and_incoming_message_digests[i].generate_r1cs_witness_from_packed(); + } + + for (size_t i = 0; i < compliance_predicate.max_arity; ++i) + { + proof[i].generate_r1cs_witness(translation_step_proofs[i]); + verifier[i].generate_r1cs_witness(); + } + +#ifdef DEBUG + get_circuit(); // force generating constraints + assert(this->pb.is_satisfied()); +#endif +} + +template +size_t mp_compliance_step_pcd_circuit_maker::field_logsize() +{ + return Fr::size_in_bits(); +} + +template +size_t mp_compliance_step_pcd_circuit_maker::field_capacity() +{ + return Fr::capacity(); +} + +template +size_t mp_compliance_step_pcd_circuit_maker::input_size_in_elts() +{ + const size_t digest_size = CRH_with_field_out_gadget::get_digest_len(); + return digest_size; +} + +template +size_t mp_compliance_step_pcd_circuit_maker::input_capacity_in_bits() +{ + return input_size_in_elts() * field_capacity(); +} + +template +size_t mp_compliance_step_pcd_circuit_maker::input_size_in_bits() +{ + return input_size_in_elts() * field_logsize(); +} + +template +mp_translation_step_pcd_circuit_maker::mp_translation_step_pcd_circuit_maker(const r1cs_ppzksnark_verification_key > &compliance_step_vk) +{ + /* allocate input of the translation MP_PCD circuit */ + mp_translation_step_pcd_circuit_input.allocate(pb, input_size_in_elts(), "mp_translation_step_pcd_circuit_input"); + + /* unpack translation step MP_PCD circuit input */ + unpacked_mp_translation_step_pcd_circuit_input.allocate(pb, mp_compliance_step_pcd_circuit_maker >::input_size_in_bits(), "unpacked_mp_translation_step_pcd_circuit_input"); + unpack_mp_translation_step_pcd_circuit_input.reset(new multipacking_gadget(pb, unpacked_mp_translation_step_pcd_circuit_input, mp_translation_step_pcd_circuit_input, field_capacity(), "unpack_mp_translation_step_pcd_circuit_input")); + + /* prepare arguments for the verifier */ + hardcoded_compliance_step_vk.reset(new r1cs_ppzksnark_preprocessed_r1cs_ppzksnark_verification_key_variable(pb, compliance_step_vk, "hardcoded_compliance_step_vk")); + proof.reset(new r1cs_ppzksnark_proof_variable(pb, "proof")); + + /* verify previous proof */ + online_verifier.reset(new r1cs_ppzksnark_online_verifier_gadget(pb, + *hardcoded_compliance_step_vk, + unpacked_mp_translation_step_pcd_circuit_input, + mp_compliance_step_pcd_circuit_maker >::field_logsize(), + *proof, + ONE, // must always accept + "verifier")); + + pb.set_input_sizes(input_size_in_elts()); +} + +template +void mp_translation_step_pcd_circuit_maker::generate_r1cs_constraints() +{ + PROFILE_CONSTRAINTS(pb, "repacking: unpack circuit input") + { + unpack_mp_translation_step_pcd_circuit_input->generate_r1cs_constraints(true); + } + + PROFILE_CONSTRAINTS(pb, "verifier for compliance proofs") + { + PROFILE_CONSTRAINTS(pb, "check that proof lies on the curve") + { + proof->generate_r1cs_constraints(); + } + + online_verifier->generate_r1cs_constraints(); + } + + PRINT_CONSTRAINT_PROFILING(); + print_indent(); printf("* Number of constraints in mp_translation_step_pcd_circuit: %zu\n", pb.num_constraints()); +} + +template +r1cs_constraint_system > mp_translation_step_pcd_circuit_maker::get_circuit() const +{ + return pb.get_constraint_system(); +} + +template +void mp_translation_step_pcd_circuit_maker::generate_r1cs_witness(const r1cs_primary_input > translation_step_input, + const r1cs_ppzksnark_proof > &prev_proof) +{ + this->pb.clear_values(); + mp_translation_step_pcd_circuit_input.fill_with_field_elements(pb, translation_step_input); + unpack_mp_translation_step_pcd_circuit_input->generate_r1cs_witness_from_packed(); + + proof->generate_r1cs_witness(prev_proof); + online_verifier->generate_r1cs_witness(); + +#ifdef DEBUG + get_circuit(); // force generating constraints + assert(this->pb.is_satisfied()); +#endif +} + +template +r1cs_primary_input > mp_translation_step_pcd_circuit_maker::get_primary_input() const +{ + return pb.primary_input(); +} + +template +r1cs_auxiliary_input > mp_translation_step_pcd_circuit_maker::get_auxiliary_input() const +{ + return pb.auxiliary_input(); +} + +template +size_t mp_translation_step_pcd_circuit_maker::field_logsize() +{ + return Fr::size_in_bits(); +} + +template +size_t mp_translation_step_pcd_circuit_maker::field_capacity() +{ + return Fr::capacity(); +} + +template +size_t mp_translation_step_pcd_circuit_maker::input_size_in_elts() +{ + return div_ceil(mp_compliance_step_pcd_circuit_maker >::input_size_in_bits(), mp_translation_step_pcd_circuit_maker::field_capacity()); +} + +template +size_t mp_translation_step_pcd_circuit_maker::input_capacity_in_bits() +{ + return input_size_in_elts() * field_capacity(); +} + +template +size_t mp_translation_step_pcd_circuit_maker::input_size_in_bits() +{ + return input_size_in_elts() * field_logsize(); +} + +template +r1cs_primary_input > get_mp_compliance_step_pcd_circuit_input(const set_commitment &commitment_to_translation_step_r1cs_vks, + const r1cs_pcd_compliance_predicate_primary_input > &primary_input) +{ + enter_block("Call to get_mp_compliance_step_pcd_circuit_input"); + typedef Fr FieldT; + + const r1cs_variable_assignment outgoing_message_as_va = primary_input.outgoing_message->as_r1cs_variable_assignment(); + bit_vector msg_bits; + for (const FieldT &elt : outgoing_message_as_va) + { + const bit_vector elt_bits = convert_field_element_to_bit_vector(elt); + msg_bits.insert(msg_bits.end(), elt_bits.begin(), elt_bits.end()); + } + + bit_vector block; + block.insert(block.end(), commitment_to_translation_step_r1cs_vks.begin(), commitment_to_translation_step_r1cs_vks.end()); + block.insert(block.end(), msg_bits.begin(), msg_bits.end()); + + enter_block("Sample CRH randomness"); + CRH_with_field_out_gadget::sample_randomness(block.size()); + leave_block("Sample CRH randomness"); + + const std::vector digest = CRH_with_field_out_gadget::get_hash(block); + leave_block("Call to get_mp_compliance_step_pcd_circuit_input"); + + return digest; +} + +template +r1cs_primary_input > get_mp_translation_step_pcd_circuit_input(const set_commitment &commitment_to_translation_step_r1cs_vks, + const r1cs_pcd_compliance_predicate_primary_input > > &primary_input) +{ + enter_block("Call to get_mp_translation_step_pcd_circuit_input"); + typedef Fr FieldT; + + const std::vector > > mp_compliance_step_pcd_circuit_input = get_mp_compliance_step_pcd_circuit_input >(commitment_to_translation_step_r1cs_vks, primary_input); + bit_vector mp_compliance_step_pcd_circuit_input_bits; + for (const Fr > &elt : mp_compliance_step_pcd_circuit_input) + { + const bit_vector elt_bits = convert_field_element_to_bit_vector > >(elt); + mp_compliance_step_pcd_circuit_input_bits.insert(mp_compliance_step_pcd_circuit_input_bits.end(), elt_bits.begin(), elt_bits.end()); + } + + mp_compliance_step_pcd_circuit_input_bits.resize(mp_translation_step_pcd_circuit_maker::input_capacity_in_bits(), false); + + const r1cs_primary_input result = pack_bit_vector_into_field_element_vector(mp_compliance_step_pcd_circuit_input_bits, mp_translation_step_pcd_circuit_maker::field_capacity()); + leave_block("Call to get_mp_translation_step_pcd_circuit_input"); + + return result; +} + +} // libsnark + +#endif // MP_PCD_CIRCUITS_TCC_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/pcd/r1cs_pcd/r1cs_mp_ppzkpcd/profiling/profile_r1cs_mp_ppzkpcd.cpp b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/pcd/r1cs_pcd/r1cs_mp_ppzkpcd/profiling/profile_r1cs_mp_ppzkpcd.cpp new file mode 100644 index 0000000..a7467c7 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/pcd/r1cs_pcd/r1cs_mp_ppzkpcd/profiling/profile_r1cs_mp_ppzkpcd.cpp @@ -0,0 +1,35 @@ +/** + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ +#include "common/default_types/r1cs_ppzkpcd_pp.hpp" +#include "zk_proof_systems/pcd/r1cs_pcd/r1cs_mp_ppzkpcd/r1cs_mp_ppzkpcd.hpp" +#include "zk_proof_systems/pcd/r1cs_pcd/r1cs_mp_ppzkpcd/examples/run_r1cs_mp_ppzkpcd.hpp" + +using namespace libsnark; + +template +void profile_tally(const size_t arity, const size_t max_layer) +{ + const size_t wordsize = 32; + const bool test_serialization = true; + const bool test_multi_type = true; + const bool test_same_type_optimization = false; + const bool bit = run_r1cs_mp_ppzkpcd_tally_example(wordsize, arity, max_layer, test_serialization, test_multi_type, test_same_type_optimization); + assert(bit); +} + +int main(void) +{ + typedef default_r1cs_ppzkpcd_pp PCD_pp; + + start_profiling(); + PCD_pp::init_public_params(); + + const size_t arity = 2; + const size_t max_layer = 2; + + profile_tally(arity, max_layer); +} diff --git a/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/pcd/r1cs_pcd/r1cs_mp_ppzkpcd/r1cs_mp_ppzkpcd.hpp b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/pcd/r1cs_pcd/r1cs_mp_ppzkpcd/r1cs_mp_ppzkpcd.hpp new file mode 100644 index 0000000..0dc0fc9 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/pcd/r1cs_pcd/r1cs_mp_ppzkpcd/r1cs_mp_ppzkpcd.hpp @@ -0,0 +1,328 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for a *multi-predicate* ppzkPCD for R1CS. + + This includes: + - class for proving key + - class for verification key + - class for processed verification key + - class for key pair (proving key & verification key) + - class for proof + - generator algorithm + - prover algorithm + - verifier algorithm + - online verifier algorithm + + The implementation follows, extends, and optimizes the approach described + in \[CTV15]. Thus, PCD is constructed from two "matched" ppzkSNARKs for R1CS. + + Acronyms: + + "R1CS" = "Rank-1 Constraint Systems" + "ppzkSNARK" = "PreProcessing Zero-Knowledge Succinct Non-interactive ARgument of Knowledge" + "ppzkPCD" = "Pre-Processing Zero-Knowledge Proof-Carrying Data" + + References: + + \[CTV15]: + "Cluster Computing in Zero Knowledge", + Alessandro Chiesa, Eran Tromer, Madars Virza, + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef R1CS_MP_PPZKPCD_HPP_ +#define R1CS_MP_PPZKPCD_HPP_ + +#include +#include + +#include "common/data_structures/set_commitment.hpp" +#include "zk_proof_systems/pcd/r1cs_pcd/ppzkpcd_compliance_predicate.hpp" +#include "zk_proof_systems/pcd/r1cs_pcd/r1cs_mp_ppzkpcd/r1cs_mp_ppzkpcd_params.hpp" +#include "zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.hpp" + +namespace libsnark { + +/******************************** Proving key ********************************/ + +template +class r1cs_mp_ppzkpcd_proving_key; + +template +std::ostream& operator<<(std::ostream &out, const r1cs_mp_ppzkpcd_proving_key &pk); + +template +std::istream& operator>>(std::istream &in, r1cs_mp_ppzkpcd_proving_key &pk); + +/** + * A proving key for the R1CS (multi-predicate) ppzkPCD. + */ +template +class r1cs_mp_ppzkpcd_proving_key { +public: + typedef typename PCD_ppT::curve_A_pp A_pp; + typedef typename PCD_ppT::curve_B_pp B_pp; + + std::vector > compliance_predicates; + + std::vector > compliance_step_r1cs_pks; + std::vector > translation_step_r1cs_pks; + + std::vector > compliance_step_r1cs_vks; + std::vector > translation_step_r1cs_vks; + + set_commitment commitment_to_translation_step_r1cs_vks; + std::vector compliance_step_r1cs_vk_membership_proofs; + + std::map compliance_predicate_name_to_idx; + + r1cs_mp_ppzkpcd_proving_key() {}; + r1cs_mp_ppzkpcd_proving_key(const r1cs_mp_ppzkpcd_proving_key &other) = default; + r1cs_mp_ppzkpcd_proving_key(r1cs_mp_ppzkpcd_proving_key &&other) = default; + r1cs_mp_ppzkpcd_proving_key(const std::vector > &compliance_predicates, + const std::vector > &compliance_step_r1cs_pk, + const std::vector > &translation_step_r1cs_pk, + const std::vector > &compliance_step_r1cs_vk, + const std::vector > &translation_step_r1cs_vk, + const set_commitment &commitment_to_translation_step_r1cs_vks, + const std::vector &compliance_step_r1cs_vk_membership_proofs, + const std::map &compliance_predicate_name_to_idx) : + compliance_predicates(compliance_predicates), + compliance_step_r1cs_pks(compliance_step_r1cs_pks), + translation_step_r1cs_pks(translation_step_r1cs_pks), + compliance_step_r1cs_vks(compliance_step_r1cs_vks), + translation_step_r1cs_vks(translation_step_r1cs_vks), + commitment_to_translation_step_r1cs_vks(commitment_to_translation_step_r1cs_vks), + compliance_step_r1cs_vk_membership_proofs(compliance_step_r1cs_vk_membership_proofs), + compliance_predicate_name_to_idx(compliance_predicate_name_to_idx) + {} + + r1cs_mp_ppzkpcd_proving_key& operator=(const r1cs_mp_ppzkpcd_proving_key &other) = default; + + size_t size_in_bits() const; + + bool is_well_formed() const; + + bool operator==(const r1cs_mp_ppzkpcd_proving_key &other) const; + friend std::ostream& operator<< (std::ostream &out, const r1cs_mp_ppzkpcd_proving_key &pk); + friend std::istream& operator>> (std::istream &in, r1cs_mp_ppzkpcd_proving_key &pk); +}; + + +/******************************* Verification key ****************************/ + +template +class r1cs_mp_ppzkpcd_verification_key; + +template +std::ostream& operator<<(std::ostream &out, const r1cs_mp_ppzkpcd_verification_key &vk); + +template +std::istream& operator>>(std::istream &in, r1cs_mp_ppzkpcd_verification_key &vk); + +/** + * A verification key for the R1CS (multi-predicate) ppzkPCD. + */ +template +class r1cs_mp_ppzkpcd_verification_key { +public: + typedef typename PCD_ppT::curve_A_pp A_pp; + typedef typename PCD_ppT::curve_B_pp B_pp; + + std::vector > compliance_step_r1cs_vks; + std::vector > translation_step_r1cs_vks; + set_commitment commitment_to_translation_step_r1cs_vks; + + r1cs_mp_ppzkpcd_verification_key() = default; + r1cs_mp_ppzkpcd_verification_key(const r1cs_mp_ppzkpcd_verification_key &other) = default; + r1cs_mp_ppzkpcd_verification_key(r1cs_mp_ppzkpcd_verification_key &&other) = default; + r1cs_mp_ppzkpcd_verification_key(const std::vector > &compliance_step_r1cs_vks, + const std::vector > &translation_step_r1cs_vks, + const set_commitment &commitment_to_translation_step_r1cs_vks) : + compliance_step_r1cs_vks(compliance_step_r1cs_vks), + translation_step_r1cs_vks(translation_step_r1cs_vks), + commitment_to_translation_step_r1cs_vks(commitment_to_translation_step_r1cs_vks) + {} + + r1cs_mp_ppzkpcd_verification_key& operator=(const r1cs_mp_ppzkpcd_verification_key &other) = default; + + size_t size_in_bits() const; + + bool operator==(const r1cs_mp_ppzkpcd_verification_key &other) const; + friend std::ostream& operator<< (std::ostream &out, const r1cs_mp_ppzkpcd_verification_key &vk); + friend std::istream& operator>> (std::istream &in, r1cs_mp_ppzkpcd_verification_key &vk); +}; + + +/************************* Processed verification key **************************/ + +template +class r1cs_mp_ppzkpcd_processed_verification_key; + +template +std::ostream& operator<<(std::ostream &out, const r1cs_mp_ppzkpcd_processed_verification_key &pvk); + +template +std::istream& operator>>(std::istream &in, r1cs_mp_ppzkpcd_processed_verification_key &pvk); + +/** + * A processed verification key for the R1CS (multi-predicate) ppzkPCD. + * + * Compared to a (non-processed) verification key, a processed verification key + * contains a small constant amount of additional pre-computed information that + * enables a faster verification time. + */ +template +class r1cs_mp_ppzkpcd_processed_verification_key { +public: + typedef typename PCD_ppT::curve_A_pp A_pp; + typedef typename PCD_ppT::curve_B_pp B_pp; + + std::vector > compliance_step_r1cs_pvks; + std::vector > translation_step_r1cs_pvks; + set_commitment commitment_to_translation_step_r1cs_vks; + + r1cs_mp_ppzkpcd_processed_verification_key() = default; + r1cs_mp_ppzkpcd_processed_verification_key(const r1cs_mp_ppzkpcd_processed_verification_key &other) = default; + r1cs_mp_ppzkpcd_processed_verification_key(r1cs_mp_ppzkpcd_processed_verification_key &&other) = default; + r1cs_mp_ppzkpcd_processed_verification_key(std::vector > &&compliance_step_r1cs_pvks, + std::vector > &&translation_step_r1cs_pvks, + const set_commitment &commitment_to_translation_step_r1cs_vks) : + compliance_step_r1cs_pvks(std::move(compliance_step_r1cs_pvks)), + translation_step_r1cs_pvks(std::move(translation_step_r1cs_pvks)), + commitment_to_translation_step_r1cs_vks(commitment_to_translation_step_r1cs_vks) + {}; + + r1cs_mp_ppzkpcd_processed_verification_key& operator=(const r1cs_mp_ppzkpcd_processed_verification_key &other) = default; + + size_t size_in_bits() const; + + bool operator==(const r1cs_mp_ppzkpcd_processed_verification_key &other) const; + friend std::ostream& operator<< (std::ostream &out, const r1cs_mp_ppzkpcd_processed_verification_key &pvk); + friend std::istream& operator>> (std::istream &in, r1cs_mp_ppzkpcd_processed_verification_key &pvk); +}; + + +/********************************** Key pair *********************************/ + +/** + * A key pair for the R1CS (multi-predicate) ppzkPC, which consists of a proving key and a verification key. + */ +template +class r1cs_mp_ppzkpcd_keypair { +public: + r1cs_mp_ppzkpcd_proving_key pk; + r1cs_mp_ppzkpcd_verification_key vk; + + r1cs_mp_ppzkpcd_keypair() = default; + r1cs_mp_ppzkpcd_keypair(r1cs_mp_ppzkpcd_keypair &&other) = default; + r1cs_mp_ppzkpcd_keypair(r1cs_mp_ppzkpcd_proving_key &&pk, + r1cs_mp_ppzkpcd_verification_key &&vk) : + pk(std::move(pk)), + vk(std::move(vk)) + {}; +}; + + +/*********************************** Proof ***********************************/ + +template +class r1cs_mp_ppzkpcd_proof; + +template +std::ostream& operator<<(std::ostream &out, const r1cs_mp_ppzkpcd_proof &proof); + +template +std::istream& operator>>(std::istream &in, r1cs_mp_ppzkpcd_proof &proof); + +/** + * A proof for the R1CS (multi-predicate) ppzkPCD. + */ +template +class r1cs_mp_ppzkpcd_proof { +public: + size_t compliance_predicate_idx; + r1cs_ppzksnark_proof r1cs_proof; + + r1cs_mp_ppzkpcd_proof() = default; + r1cs_mp_ppzkpcd_proof(const size_t compliance_predicate_idx, + const r1cs_ppzksnark_proof &r1cs_proof) : + compliance_predicate_idx(compliance_predicate_idx), + r1cs_proof(r1cs_proof) + {} + + size_t size_in_bits() const; + + bool operator==(const r1cs_mp_ppzkpcd_proof &other) const; + friend std::ostream& operator<< (std::ostream &out, const r1cs_mp_ppzkpcd_proof &proof); + friend std::istream& operator>> (std::istream &in, r1cs_mp_ppzkpcd_proof &proof); +}; + + +/***************************** Main algorithms *******************************/ + +/** + * A generator algorithm for the R1CS (multi-predicate) ppzkPCD. + * + * Given a vector of compliance predicates, this algorithm produces proving and verification keys for the vector. + */ +template +r1cs_mp_ppzkpcd_keypair r1cs_mp_ppzkpcd_generator(const std::vector > &compliance_predicates); + +/** + * A prover algorithm for the R1CS (multi-predicate) ppzkPCD. + * + * Given a proving key, name of chosen compliance predicate, inputs for the + * compliance predicate, and proofs for the predicate's input messages, this + * algorithm produces a proof (of knowledge) that attests to the compliance of + * the output message. + */ +template +r1cs_mp_ppzkpcd_proof r1cs_mp_ppzkpcd_prover(const r1cs_mp_ppzkpcd_proving_key &pk, + const size_t compliance_predicate_name, + const r1cs_mp_ppzkpcd_primary_input &primary_input, + const r1cs_mp_ppzkpcd_auxiliary_input &auxiliary_input, + const std::vector > &incoming_proofs); + +/* + Below are two variants of verifier algorithm for the R1CS (multi-predicate) ppzkPCD. + + These are the two cases that arise from whether the verifier accepts a + (non-processed) verification key or, instead, a processed verification key. + In the latter case, we call the algorithm an "online verifier". +*/ + +/** + * A verifier algorithm for the R1CS (multi-predicate) ppzkPCD that + * accepts a non-processed verification key. + */ +template +bool r1cs_mp_ppzkpcd_verifier(const r1cs_mp_ppzkpcd_verification_key &vk, + const r1cs_mp_ppzkpcd_primary_input &primary_input, + const r1cs_mp_ppzkpcd_proof &proof); + +/** + * Convert a (non-processed) verification key into a processed verification key. + */ +template +r1cs_mp_ppzkpcd_processed_verification_key r1cs_mp_ppzkpcd_process_vk(const r1cs_mp_ppzkpcd_verification_key &vk); + +/** + * A verifier algorithm for the R1CS (multi-predicate) ppzkPCD that + * accepts a processed verification key. + */ +template +bool r1cs_mp_ppzkpcd_online_verifier(const r1cs_mp_ppzkpcd_processed_verification_key &pvk, + const r1cs_mp_ppzkpcd_primary_input &primary_input, + const r1cs_mp_ppzkpcd_proof &proof); + +} // libsnark + +#include "zk_proof_systems/pcd/r1cs_pcd/r1cs_mp_ppzkpcd/r1cs_mp_ppzkpcd.tcc" + +#endif // R1CS_MP_PPZKPCD_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/pcd/r1cs_pcd/r1cs_mp_ppzkpcd/r1cs_mp_ppzkpcd.tcc b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/pcd/r1cs_pcd/r1cs_mp_ppzkpcd/r1cs_mp_ppzkpcd.tcc new file mode 100644 index 0000000..407a612 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/pcd/r1cs_pcd/r1cs_mp_ppzkpcd/r1cs_mp_ppzkpcd.tcc @@ -0,0 +1,517 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for a *multi-predicate* ppzkPCD for R1CS. + + See r1cs_mp_ppzkpcd.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef R1CS_MP_PPZKPCD_TCC_ +#define R1CS_MP_PPZKPCD_TCC_ + +#include +#include +#include + +#include "common/profiling.hpp" +#include "common/utils.hpp" +#include "zk_proof_systems/pcd/r1cs_pcd/r1cs_mp_ppzkpcd/mp_pcd_circuits.hpp" + +namespace libsnark { + +template +size_t r1cs_mp_ppzkpcd_proving_key::size_in_bits() const +{ + const size_t num_predicates = compliance_predicates.size(); + + size_t result = 0; + for (size_t i = 0; i < num_predicates; ++i) + { + result += (compliance_predicates[i].size_in_bits() + + compliance_step_r1cs_pks[i].size_in_bits() + + translation_step_r1cs_pks[i].size_in_bits() + + compliance_step_r1cs_vks[i].size_in_bits() + + translation_step_r1cs_vks[i].size_in_bits() + + compliance_step_r1cs_vk_membership_proofs[i].size_in_bits()); + } + result += commitment_to_translation_step_r1cs_vks.size(); + + return result; +} + +template +bool r1cs_mp_ppzkpcd_proving_key::is_well_formed() const +{ + const size_t num_predicates = compliance_predicates.size(); + + bool result; + result = result && (compliance_step_r1cs_pks.size() == num_predicates); + result = result && (translation_step_r1cs_pks.size() == num_predicates); + result = result && (compliance_step_r1cs_vks.size() == num_predicates); + result = result && (translation_step_r1cs_vks.size() == num_predicates); + result = result && (compliance_step_r1cs_vk_membership_proofs.size() == num_predicates); + + return result; +} + +template +bool r1cs_mp_ppzkpcd_proving_key::operator==(const r1cs_mp_ppzkpcd_proving_key &other) const +{ + return (this->compliance_predicates == other.compliance_predicates && + this->compliance_step_r1cs_pks == other.compliance_step_r1cs_pks && + this->translation_step_r1cs_pks == other.translation_step_r1cs_pks && + this->compliance_step_r1cs_vks == other.compliance_step_r1cs_vks && + this->translation_step_r1cs_vks == other.translation_step_r1cs_vks && + this->commitment_to_translation_step_r1cs_vks == other.commitment_to_translation_step_r1cs_vks && + this->compliance_step_r1cs_vk_membership_proofs == other.compliance_step_r1cs_vk_membership_proofs && + this->compliance_predicate_name_to_idx == other.compliance_predicate_name_to_idx); +} + +template +std::ostream& operator<<(std::ostream &out, const r1cs_mp_ppzkpcd_proving_key &pk) +{ + out << pk.compliance_predicates; + out << pk.compliance_step_r1cs_pks; + out << pk.translation_step_r1cs_pks; + out << pk.compliance_step_r1cs_vks; + out << pk.translation_step_r1cs_vks; + output_bool_vector(out, pk.commitment_to_translation_step_r1cs_vks); + out << pk.compliance_step_r1cs_vk_membership_proofs; + out << pk.compliance_predicate_name_to_idx; + + return out; +} + +template +std::istream& operator>>(std::istream &in, r1cs_mp_ppzkpcd_proving_key &pk) +{ + in >> pk.compliance_predicates; + in >> pk.compliance_step_r1cs_pks; + in >> pk.translation_step_r1cs_pks; + in >> pk.compliance_step_r1cs_vks; + in >> pk.translation_step_r1cs_vks; + input_bool_vector(in, pk.commitment_to_translation_step_r1cs_vks); + in >> pk.compliance_step_r1cs_vk_membership_proofs; + in >> pk.compliance_predicate_name_to_idx; + + return in; +} + +template +size_t r1cs_mp_ppzkpcd_verification_key::size_in_bits() const +{ + const size_t num_predicates = compliance_step_r1cs_vks.size(); + + size_t result = 0; + for (size_t i = 0; i < num_predicates; ++i) + { + result += (compliance_step_r1cs_vks[i].size_in_bits() + + translation_step_r1cs_vks[i].size_in_bits()); + } + + result += commitment_to_translation_step_r1cs_vks.size(); + + return result; +} + +template +bool r1cs_mp_ppzkpcd_verification_key::operator==(const r1cs_mp_ppzkpcd_verification_key &other) const +{ + return (this->compliance_step_r1cs_vks == other.compliance_step_r1cs_vks && + this->translation_step_r1cs_vks == other.translation_step_r1cs_vks && + this->commitment_to_translation_step_r1cs_vks == other.commitment_to_translation_step_r1cs_vks); +} + +template +std::ostream& operator<<(std::ostream &out, const r1cs_mp_ppzkpcd_verification_key &vk) +{ + out << vk.compliance_step_r1cs_vks; + out << vk.translation_step_r1cs_vks; + output_bool_vector(out, vk.commitment_to_translation_step_r1cs_vks); + + return out; +} + +template +std::istream& operator>>(std::istream &in, r1cs_mp_ppzkpcd_verification_key &vk) +{ + in >> vk.compliance_step_r1cs_vks; + in >> vk.translation_step_r1cs_vks; + input_bool_vector(in, vk.commitment_to_translation_step_r1cs_vks); + + return in; +} + +template +size_t r1cs_mp_ppzkpcd_processed_verification_key::size_in_bits() const +{ + const size_t num_predicates = compliance_step_r1cs_pvks.size(); + + size_t result = 0; + for (size_t i = 0; i < num_predicates; ++i) + { + result += (compliance_step_r1cs_pvks[i].size_in_bits() + + translation_step_r1cs_pvks[i].size_in_bits()); + } + + result += commitment_to_translation_step_r1cs_vks.size(); + + return result; +} + +template +bool r1cs_mp_ppzkpcd_processed_verification_key::operator==(const r1cs_mp_ppzkpcd_processed_verification_key &other) const +{ + return (this->compliance_step_r1cs_pvks == other.compliance_step_r1cs_pvks && + this->translation_step_r1cs_pvks == other.translation_step_r1cs_pvks && + this->commitment_to_translation_step_r1cs_vks == other.commitment_to_translation_step_r1cs_vks); +} + +template +std::ostream& operator<<(std::ostream &out, const r1cs_mp_ppzkpcd_processed_verification_key &pvk) +{ + out << pvk.compliance_step_r1cs_pvks; + out << pvk.translation_step_r1cs_pvks; + output_bool_vector(out, pvk.commitment_to_translation_step_r1cs_vks); + + return out; +} + +template +std::istream& operator>>(std::istream &in, r1cs_mp_ppzkpcd_processed_verification_key &pvk) +{ + in >> pvk.compliance_step_r1cs_pvks; + in >> pvk.translation_step_r1cs_pvks; + input_bool_vector(in, pvk.commitment_to_translation_step_r1cs_vks); + + return in; +} + +template +bool r1cs_mp_ppzkpcd_proof::operator==(const r1cs_mp_ppzkpcd_proof &other) const +{ + return (this->compliance_predicate_idx == other.compliance_predicate_idx && + this->r1cs_proof == other.r1cs_proof); +} + +template +std::ostream& operator<<(std::ostream &out, const r1cs_mp_ppzkpcd_proof &proof) +{ + out << proof.compliance_predicate_idx << "\n"; + out << proof.r1cs_proof; + + return out; +} + +template +std::istream& operator>>(std::istream &in, r1cs_mp_ppzkpcd_proof &proof) +{ + in >> proof.compliance_predicate_idx; + consume_newline(in); + in >> proof.r1cs_proof; + + return in; +} + +template +r1cs_mp_ppzkpcd_keypair r1cs_mp_ppzkpcd_generator(const std::vector > &compliance_predicates) +{ + assert(Fr::mod == Fq::mod); + assert(Fq::mod == Fr::mod); + + typedef typename PCD_ppT::curve_A_pp curve_A_pp; + typedef typename PCD_ppT::curve_B_pp curve_B_pp; + + typedef Fr FieldT_A; + typedef Fr FieldT_B; + + enter_block("Call to r1cs_mp_ppzkpcd_generator"); + + r1cs_mp_ppzkpcd_keypair keypair; + const size_t translation_input_size = mp_translation_step_pcd_circuit_maker::input_size_in_elts(); + const size_t vk_size_in_bits = r1cs_ppzksnark_verification_key_variable::size_in_bits(translation_input_size); + printf("%zu %zu\n", translation_input_size, vk_size_in_bits); + + set_commitment_accumulator > all_translation_vks(compliance_predicates.size(), vk_size_in_bits); + + enter_block("Perform type checks"); + std::map type_counts; + + for (auto &cp : compliance_predicates) + { + type_counts[cp.type] += 1; + } + + for (auto &cp : compliance_predicates) + { + if (cp.relies_on_same_type_inputs) + { + for (size_t type : cp.accepted_input_types) + { + assert(type_counts[type] == 1); /* each of accepted_input_types must be unique */ + } + } + else + { + assert(cp.accepted_input_types.empty()); + } + } + leave_block("Perform type checks"); + + for (size_t i = 0; i < compliance_predicates.size(); ++i) + { + enter_block(FORMAT("", "Process predicate %zu (with name %zu and type %zu)", i, compliance_predicates[i].name, compliance_predicates[i].type)); + assert(compliance_predicates[i].is_well_formed()); + + enter_block("Construct compliance step PCD circuit"); + mp_compliance_step_pcd_circuit_maker mp_compliance_step_pcd_circuit(compliance_predicates[i], compliance_predicates.size()); + mp_compliance_step_pcd_circuit.generate_r1cs_constraints(); + r1cs_constraint_system mp_compliance_step_pcd_circuit_cs = mp_compliance_step_pcd_circuit.get_circuit(); + leave_block("Construct compliance step PCD circuit"); + + enter_block("Generate key pair for compliance step PCD circuit"); + r1cs_ppzksnark_keypair mp_compliance_step_keypair = r1cs_ppzksnark_generator(mp_compliance_step_pcd_circuit_cs); + leave_block("Generate key pair for compliance step PCD circuit"); + + enter_block("Construct translation step PCD circuit"); + mp_translation_step_pcd_circuit_maker mp_translation_step_pcd_circuit(mp_compliance_step_keypair.vk); + mp_translation_step_pcd_circuit.generate_r1cs_constraints(); + r1cs_constraint_system mp_translation_step_pcd_circuit_cs = mp_translation_step_pcd_circuit.get_circuit(); + leave_block("Construct translation step PCD circuit"); + + enter_block("Generate key pair for translation step PCD circuit"); + r1cs_ppzksnark_keypair mp_translation_step_keypair = r1cs_ppzksnark_generator(mp_translation_step_pcd_circuit_cs); + leave_block("Generate key pair for translation step PCD circuit"); + + enter_block("Augment set of translation step verification keys"); + const bit_vector vk_bits = r1cs_ppzksnark_verification_key_variable::get_verification_key_bits(mp_translation_step_keypair.vk); + all_translation_vks.add(vk_bits); + leave_block("Augment set of translation step verification keys"); + + enter_block("Update r1cs_mp_ppzkpcd keypair"); + keypair.pk.compliance_predicates.emplace_back(compliance_predicates[i]); + keypair.pk.compliance_step_r1cs_pks.emplace_back(mp_compliance_step_keypair.pk); + keypair.pk.translation_step_r1cs_pks.emplace_back(mp_translation_step_keypair.pk); + keypair.pk.compliance_step_r1cs_vks.emplace_back(mp_compliance_step_keypair.vk); + keypair.pk.translation_step_r1cs_vks.emplace_back(mp_translation_step_keypair.vk); + const size_t cp_name = compliance_predicates[i].name; + assert(keypair.pk.compliance_predicate_name_to_idx.find(cp_name) == keypair.pk.compliance_predicate_name_to_idx.end()); // all names must be distinct + keypair.pk.compliance_predicate_name_to_idx[cp_name] = i; + + keypair.vk.compliance_step_r1cs_vks.emplace_back(mp_compliance_step_keypair.vk); + keypair.vk.translation_step_r1cs_vks.emplace_back(mp_translation_step_keypair.vk); + leave_block("Update r1cs_mp_ppzkpcd keypair"); + + leave_block(FORMAT("", "Process predicate %zu (with name %zu and type %zu)", i, compliance_predicates[i].name, compliance_predicates[i].type)); + } + + enter_block("Compute set commitment and corresponding membership proofs"); + const set_commitment cm = all_translation_vks.get_commitment(); + keypair.pk.commitment_to_translation_step_r1cs_vks = cm; + keypair.vk.commitment_to_translation_step_r1cs_vks = cm; + for (size_t i = 0; i < compliance_predicates.size(); ++i) + { + const bit_vector vk_bits = r1cs_ppzksnark_verification_key_variable::get_verification_key_bits(keypair.vk.translation_step_r1cs_vks[i]); + const set_membership_proof proof = all_translation_vks.get_membership_proof(vk_bits); + + keypair.pk.compliance_step_r1cs_vk_membership_proofs.emplace_back(proof); + } + leave_block("Compute set commitment and corresponding membership proofs"); + + print_indent(); print_mem("in generator"); + leave_block("Call to r1cs_mp_ppzkpcd_generator"); + + return keypair; +} + +template +r1cs_mp_ppzkpcd_proof r1cs_mp_ppzkpcd_prover(const r1cs_mp_ppzkpcd_proving_key &pk, + const size_t compliance_predicate_name, + const r1cs_mp_ppzkpcd_primary_input &primary_input, + const r1cs_mp_ppzkpcd_auxiliary_input &auxiliary_input, + const std::vector > &prev_proofs) +{ + typedef typename PCD_ppT::curve_A_pp curve_A_pp; + typedef typename PCD_ppT::curve_B_pp curve_B_pp; + + typedef Fr FieldT_A; + typedef Fr FieldT_B; + + enter_block("Call to r1cs_mp_ppzkpcd_prover"); + +#ifdef DEBUG + printf("Compliance predicate name: %zu\n", compliance_predicate_name); +#endif + auto it = pk.compliance_predicate_name_to_idx.find(compliance_predicate_name); + assert(it != pk.compliance_predicate_name_to_idx.end()); + const size_t compliance_predicate_idx = it->second; + +#ifdef DEBUG + printf("Outgoing message:\n"); + primary_input.outgoing_message->print(); +#endif + + enter_block("Prove compliance step"); + assert(compliance_predicate_idx < pk.compliance_predicates.size()); + assert(prev_proofs.size() <= pk.compliance_predicates[compliance_predicate_idx].max_arity); + + const size_t arity = prev_proofs.size(); + const size_t max_arity = pk.compliance_predicates[compliance_predicate_idx].max_arity; + + if (pk.compliance_predicates[compliance_predicate_idx].relies_on_same_type_inputs) + { + const size_t input_predicate_idx = prev_proofs[0].compliance_predicate_idx; + for (size_t i = 1; i < arity; ++i) + { + assert(prev_proofs[i].compliance_predicate_idx == input_predicate_idx); + } + } + + std::vector > padded_proofs(max_arity); + for (size_t i = 0; i < arity; ++i) + { + padded_proofs[i] = prev_proofs[i].r1cs_proof; + } + + std::vector > translation_step_vks; + std::vector membership_proofs; + + for (size_t i = 0; i < arity; ++i) + { + const size_t input_predicate_idx = prev_proofs[i].compliance_predicate_idx; + translation_step_vks.emplace_back(pk.translation_step_r1cs_vks[input_predicate_idx]); + membership_proofs.emplace_back(pk.compliance_step_r1cs_vk_membership_proofs[input_predicate_idx]); + +#ifdef DEBUG + if (auxiliary_input.incoming_messages[i]->type != 0) + { + printf("check proof for message %zu\n", i); + const r1cs_primary_input translated_msg = get_mp_translation_step_pcd_circuit_input(pk.commitment_to_translation_step_r1cs_vks, + auxiliary_input.incoming_messages[i]); + const bool bit = r1cs_ppzksnark_verifier_strong_IC(translation_step_vks[i], translated_msg, padded_proofs[i]); + assert(bit); + } + else + { + printf("message %zu is base case\n", i); + } +#endif + } + + /* pad with dummy vks/membership proofs */ + for (size_t i = arity; i < max_arity; ++i) + { + printf("proof %zu will be a dummy\n", arity); + translation_step_vks.emplace_back(pk.translation_step_r1cs_vks[0]); + membership_proofs.emplace_back(pk.compliance_step_r1cs_vk_membership_proofs[0]); + } + + mp_compliance_step_pcd_circuit_maker mp_compliance_step_pcd_circuit(pk.compliance_predicates[compliance_predicate_idx], pk.compliance_predicates.size()); + + mp_compliance_step_pcd_circuit.generate_r1cs_witness(pk.commitment_to_translation_step_r1cs_vks, + translation_step_vks, + membership_proofs, + primary_input, + auxiliary_input, + padded_proofs); + + const r1cs_primary_input compliance_step_primary_input = mp_compliance_step_pcd_circuit.get_primary_input(); + const r1cs_auxiliary_input compliance_step_auxiliary_input = mp_compliance_step_pcd_circuit.get_auxiliary_input(); + const r1cs_ppzksnark_proof compliance_step_proof = r1cs_ppzksnark_prover(pk.compliance_step_r1cs_pks[compliance_predicate_idx], compliance_step_primary_input, compliance_step_auxiliary_input); + leave_block("Prove compliance step"); + +#ifdef DEBUG + const r1cs_primary_input compliance_step_input = get_mp_compliance_step_pcd_circuit_input(pk.commitment_to_translation_step_r1cs_vks, primary_input.outgoing_message); + const bool compliance_step_ok = r1cs_ppzksnark_verifier_strong_IC(pk.compliance_step_r1cs_vks[compliance_predicate_idx], compliance_step_input, compliance_step_proof); + assert(compliance_step_ok); +#endif + + enter_block("Prove translation step"); + mp_translation_step_pcd_circuit_maker mp_translation_step_pcd_circuit(pk.compliance_step_r1cs_vks[compliance_predicate_idx]); + + const r1cs_primary_input translation_step_primary_input = get_mp_translation_step_pcd_circuit_input(pk.commitment_to_translation_step_r1cs_vks, primary_input); + mp_translation_step_pcd_circuit.generate_r1cs_witness(translation_step_primary_input, compliance_step_proof); + const r1cs_auxiliary_input translation_step_auxiliary_input = mp_translation_step_pcd_circuit.get_auxiliary_input(); + + const r1cs_ppzksnark_proof translation_step_proof = r1cs_ppzksnark_prover(pk.translation_step_r1cs_pks[compliance_predicate_idx], translation_step_primary_input, translation_step_auxiliary_input); + + leave_block("Prove translation step"); + +#ifdef DEBUG + const bool translation_step_ok = r1cs_ppzksnark_verifier_strong_IC(pk.translation_step_r1cs_vks[compliance_predicate_idx], translation_step_primary_input, translation_step_proof); + assert(translation_step_ok); +#endif + + print_indent(); print_mem("in prover"); + leave_block("Call to r1cs_mp_ppzkpcd_prover"); + + r1cs_mp_ppzkpcd_proof result; + result.compliance_predicate_idx = compliance_predicate_idx; + result.r1cs_proof = translation_step_proof; + return result; +} + +template +bool r1cs_mp_ppzkpcd_online_verifier(const r1cs_mp_ppzkpcd_processed_verification_key &pvk, + const r1cs_mp_ppzkpcd_primary_input &primary_input, + const r1cs_mp_ppzkpcd_proof &proof) +{ + typedef typename PCD_ppT::curve_B_pp curve_B_pp; + + enter_block("Call to r1cs_mp_ppzkpcd_online_verifier"); + const r1cs_primary_input > r1cs_input = get_mp_translation_step_pcd_circuit_input(pvk.commitment_to_translation_step_r1cs_vks, primary_input); + const bool result = r1cs_ppzksnark_online_verifier_strong_IC(pvk.translation_step_r1cs_pvks[proof.compliance_predicate_idx], r1cs_input, proof.r1cs_proof); + + print_indent(); print_mem("in online verifier"); + leave_block("Call to r1cs_mp_ppzkpcd_online_verifier"); + return result; +} + +template +r1cs_mp_ppzkpcd_processed_verification_key r1cs_mp_ppzkpcd_process_vk(const r1cs_mp_ppzkpcd_verification_key &vk) +{ + typedef typename PCD_ppT::curve_A_pp curve_A_pp; + typedef typename PCD_ppT::curve_B_pp curve_B_pp; + + enter_block("Call to r1cs_mp_ppzkpcd_processed_verification_key"); + + r1cs_mp_ppzkpcd_processed_verification_key result; + result.commitment_to_translation_step_r1cs_vks = vk.commitment_to_translation_step_r1cs_vks; + + for (size_t i = 0; i < vk.compliance_step_r1cs_vks.size(); ++i) + { + const r1cs_ppzksnark_processed_verification_key compliance_step_r1cs_pvk = r1cs_ppzksnark_verifier_process_vk(vk.compliance_step_r1cs_vks[i]); + const r1cs_ppzksnark_processed_verification_key translation_step_r1cs_pvk = r1cs_ppzksnark_verifier_process_vk(vk.translation_step_r1cs_vks[i]); + + result.compliance_step_r1cs_pvks.emplace_back(compliance_step_r1cs_pvk); + result.translation_step_r1cs_pvks.emplace_back(translation_step_r1cs_pvk); + } + leave_block("Call to r1cs_mp_ppzkpcd_processed_verification_key"); + + return result; +} + + +template +bool r1cs_mp_ppzkpcd_verifier(const r1cs_mp_ppzkpcd_verification_key &vk, + const r1cs_mp_ppzkpcd_primary_input &primary_input, + const r1cs_mp_ppzkpcd_proof &proof) +{ + enter_block("Call to r1cs_mp_ppzkpcd_verifier"); + r1cs_mp_ppzkpcd_processed_verification_key pvk = r1cs_mp_ppzkpcd_process_vk(vk); + const bool result = r1cs_mp_ppzkpcd_online_verifier(pvk, primary_input, proof); + + print_indent(); print_mem("in verifier"); + leave_block("Call to r1cs_mp_ppzkpcd_verifier"); + return result; +} + + +} // libsnark + +#endif // R1CS_MP_PPZKPCD_TCC_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/pcd/r1cs_pcd/r1cs_mp_ppzkpcd/r1cs_mp_ppzkpcd_params.hpp b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/pcd/r1cs_pcd/r1cs_mp_ppzkpcd/r1cs_mp_ppzkpcd_params.hpp new file mode 100644 index 0000000..b2d9c58 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/pcd/r1cs_pcd/r1cs_mp_ppzkpcd/r1cs_mp_ppzkpcd_params.hpp @@ -0,0 +1,38 @@ +/** @file + ***************************************************************************** + + Parameters for *multi-predicate* ppzkPCD for R1CS. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef R1CS_MP_PPZKPCD_PARAMS_HPP_ +#define R1CS_MP_PPZKPCD_PARAMS_HPP_ + +#include "algebra/curves/public_params.hpp" +#include "zk_proof_systems/pcd/r1cs_pcd/compliance_predicate/compliance_predicate.hpp" +#include "zk_proof_systems/pcd/r1cs_pcd/r1cs_pcd_params.hpp" + +namespace libsnark { + +template +using r1cs_mp_ppzkpcd_compliance_predicate = r1cs_pcd_compliance_predicate >; + +template +using r1cs_mp_ppzkpcd_message = r1cs_pcd_message >; + +template +using r1cs_mp_ppzkpcd_local_data = r1cs_pcd_local_data >; + +template +using r1cs_mp_ppzkpcd_primary_input = r1cs_pcd_compliance_predicate_primary_input >; + +template +using r1cs_mp_ppzkpcd_auxiliary_input = r1cs_pcd_compliance_predicate_auxiliary_input >; + +} // libsnark + +#endif // R1CS_MP_PPZKPCD_PARAMS_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/pcd/r1cs_pcd/r1cs_mp_ppzkpcd/tests/test_r1cs_mp_ppzkpcd.cpp b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/pcd/r1cs_pcd/r1cs_mp_ppzkpcd/tests/test_r1cs_mp_ppzkpcd.cpp new file mode 100644 index 0000000..252e43b --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/pcd/r1cs_pcd/r1cs_mp_ppzkpcd/tests/test_r1cs_mp_ppzkpcd.cpp @@ -0,0 +1,34 @@ +/** + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ +#include "common/default_types/r1cs_ppzkpcd_pp.hpp" +#include "zk_proof_systems/pcd/r1cs_pcd/r1cs_mp_ppzkpcd/examples/run_r1cs_mp_ppzkpcd.hpp" + +using namespace libsnark; + +template +void test_tally(const size_t arity, const size_t max_layer, const bool test_multi_type, const bool test_same_type_optimization) + +{ + const size_t wordsize = 32; + const bool test_serialization = true; + const bool bit = run_r1cs_mp_ppzkpcd_tally_example(wordsize, arity, max_layer, test_serialization, test_multi_type, test_same_type_optimization); + assert(bit); +} + +int main(void) +{ + start_profiling(); + default_r1cs_ppzkpcd_pp::init_public_params(); + + const size_t max_arity = 2; + const size_t max_layer = 2; + + test_tally(max_arity, max_layer, false, false); + test_tally(max_arity, max_layer, false, true); + test_tally(max_arity, max_layer, true, false); + test_tally(max_arity, max_layer, true, true); +} diff --git a/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/pcd/r1cs_pcd/r1cs_pcd_params.hpp b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/pcd/r1cs_pcd/r1cs_pcd_params.hpp new file mode 100644 index 0000000..6f634a3 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/pcd/r1cs_pcd/r1cs_pcd_params.hpp @@ -0,0 +1,43 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ +#ifndef R1CS_PCD_PARAMS_HPP_ +#define R1CS_PCD_PARAMS_HPP_ + +#include +#include "zk_proof_systems/pcd/r1cs_pcd/compliance_predicate/compliance_predicate.hpp" + +namespace libsnark { + +template +class r1cs_pcd_compliance_predicate_primary_input { +public: + std::shared_ptr > outgoing_message; + + r1cs_pcd_compliance_predicate_primary_input(const std::shared_ptr > &outgoing_message) : outgoing_message(outgoing_message) {} + r1cs_primary_input as_r1cs_primary_input() const; +}; + +template +class r1cs_pcd_compliance_predicate_auxiliary_input { +public: + std::vector > > incoming_messages; + std::shared_ptr > local_data; + r1cs_pcd_witness witness; + + r1cs_pcd_compliance_predicate_auxiliary_input(const std::vector > > &incoming_messages, + const std::shared_ptr > &local_data, + const r1cs_pcd_witness &witness) : + incoming_messages(incoming_messages), local_data(local_data), witness(witness) {} + + r1cs_auxiliary_input as_r1cs_auxiliary_input(const std::vector &incoming_message_payload_lengths) const; +}; + +} // libsnark + +#include "zk_proof_systems/pcd/r1cs_pcd/r1cs_pcd_params.tcc" + +#endif // R1CS_PCD_PARAMS_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/pcd/r1cs_pcd/r1cs_pcd_params.tcc b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/pcd/r1cs_pcd/r1cs_pcd_params.tcc new file mode 100644 index 0000000..5fc927d --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/pcd/r1cs_pcd/r1cs_pcd_params.tcc @@ -0,0 +1,51 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ +#ifndef R1CS_PCD_PARAMS_TCC_ +#define R1CS_PCD_PARAMS_TCC_ + +namespace libsnark { + +template +r1cs_primary_input r1cs_pcd_compliance_predicate_primary_input::as_r1cs_primary_input() const +{ + return outgoing_message->as_r1cs_variable_assignment(); +} + +template +r1cs_auxiliary_input r1cs_pcd_compliance_predicate_auxiliary_input::as_r1cs_auxiliary_input(const std::vector &incoming_message_payload_lengths) const +{ + const size_t arity = incoming_messages.size(); + + r1cs_auxiliary_input result; + result.emplace_back(FieldT(arity)); + + const size_t max_arity = incoming_message_payload_lengths.size(); + assert(arity <= max_arity); + + for (size_t i = 0; i < arity; ++i) + { + const r1cs_variable_assignment msg_as_r1cs_va = incoming_messages[i]->as_r1cs_variable_assignment(); + assert(msg_as_r1cs_va.size() == (1 + incoming_message_payload_lengths[i])); + result.insert(result.end(), msg_as_r1cs_va.begin(), msg_as_r1cs_va.end()); + } + + /* pad with dummy messages of appropriate size */ + for (size_t i = arity; i < max_arity; ++i) + { + result.resize(result.size() + (1 + incoming_message_payload_lengths[i]), FieldT::zero()); + } + + const r1cs_variable_assignment local_data_as_r1cs_va = local_data->as_r1cs_variable_assignment(); + result.insert(result.end(), local_data_as_r1cs_va.begin(), local_data_as_r1cs_va.end()); + result.insert(result.end(), witness.begin(), witness.end()); + + return result; +} + +} // libsnark + +#endif // R1CS_PCD_PARAMS_TCC_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/pcd/r1cs_pcd/r1cs_sp_ppzkpcd/examples/run_r1cs_sp_ppzkpcd.hpp b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/pcd/r1cs_pcd/r1cs_sp_ppzkpcd/examples/run_r1cs_sp_ppzkpcd.hpp new file mode 100644 index 0000000..1ccd3dd --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/pcd/r1cs_pcd/r1cs_sp_ppzkpcd/examples/run_r1cs_sp_ppzkpcd.hpp @@ -0,0 +1,35 @@ +/** @file + ***************************************************************************** + + Declaration of functionality that runs the R1CS single-predicate ppzkPCD + for a compliance predicate example. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef RUN_R1CS_SP_PPZKPCD_HPP_ +#define RUN_R1CS_SP_PPZKPCD_HPP_ + +namespace libsnark { + +/** + * Runs the single-predicate ppzkPCD (generator, prover, and verifier) for the + * "tally compliance predicate", of a given wordsize, arity, and depth. + * + * Optionally, also test the serialization routines for keys and proofs. + * (This takes additional time.) + */ +template +bool run_r1cs_sp_ppzkpcd_tally_example(const size_t wordsize, + const size_t arity, + const size_t depth, + const bool test_serialization); + +} // libsnark + +#include "zk_proof_systems/pcd/r1cs_pcd/r1cs_sp_ppzkpcd/examples/run_r1cs_sp_ppzkpcd.tcc" + +#endif // RUN_R1CS_SP_PPZKPCD_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/pcd/r1cs_pcd/r1cs_sp_ppzkpcd/examples/run_r1cs_sp_ppzkpcd.tcc b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/pcd/r1cs_pcd/r1cs_sp_ppzkpcd/examples/run_r1cs_sp_ppzkpcd.tcc new file mode 100644 index 0000000..42d0084 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/pcd/r1cs_pcd/r1cs_sp_ppzkpcd/examples/run_r1cs_sp_ppzkpcd.tcc @@ -0,0 +1,151 @@ +/** @file + ***************************************************************************** + + Implementation of functionality that runs the R1CS single-predicate ppzkPCD + for a compliance predicate example. + + See run_r1cs_sp_ppzkpcd.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef RUN_R1CS_SP_PPZKPCD_TCC_ +#define RUN_R1CS_SP_PPZKPCD_TCC_ + +#include "zk_proof_systems/pcd/r1cs_pcd/r1cs_sp_ppzkpcd/r1cs_sp_ppzkpcd.hpp" + +#include "zk_proof_systems/pcd/r1cs_pcd/compliance_predicate/examples/tally_cp.hpp" + +namespace libsnark { + +template +bool run_r1cs_sp_ppzkpcd_tally_example(const size_t wordsize, + const size_t arity, + const size_t depth, + const bool test_serialization) +{ + enter_block("Call to run_r1cs_sp_ppzkpcd_tally_example"); + + typedef Fr FieldT; + + bool all_accept = true; + + enter_block("Generate all messages"); + size_t tree_size = 0; + size_t nodes_in_layer = 1; + for (size_t layer = 0; layer <= depth; ++layer) + { + tree_size += nodes_in_layer; + nodes_in_layer *= arity; + } + std::vector tree_elems(tree_size); + for (size_t i = 0; i < tree_size; ++i) + { + tree_elems[i] = std::rand() % 10; + printf("tree_elems[%zu] = %zu\n", i, tree_elems[i]); + } + leave_block("Generate all messages"); + + std::vector > tree_proofs(tree_size); + std::vector > > tree_messages(tree_size); + + enter_block("Generate compliance predicate"); + const size_t type = 1; + tally_cp_handler tally(type, arity, wordsize); + tally.generate_r1cs_constraints(); + r1cs_pcd_compliance_predicate tally_cp = tally.get_compliance_predicate(); + leave_block("Generate compliance predicate"); + + print_header("R1CS ppzkPCD Generator"); + r1cs_sp_ppzkpcd_keypair keypair = r1cs_sp_ppzkpcd_generator(tally_cp); + + print_header("Process verification key"); + r1cs_sp_ppzkpcd_processed_verification_key pvk = r1cs_sp_ppzkpcd_process_vk(keypair.vk); + + if (test_serialization) + { + enter_block("Test serialization of keys"); + keypair.pk = reserialize >(keypair.pk); + keypair.vk = reserialize >(keypair.vk); + pvk = reserialize >(pvk); + leave_block("Test serialization of keys"); + } + + std::shared_ptr > base_msg = tally.get_base_case_message(); + nodes_in_layer /= arity; + for (long layer = depth; layer >= 0; --layer, nodes_in_layer /= arity) + { + for (size_t i = 0; i < nodes_in_layer; ++i) + { + const size_t cur_idx = (nodes_in_layer - 1) / (arity - 1) + i; + + std::vector > > msgs(arity, base_msg); + std::vector > proofs(arity); + + const bool base_case = (arity * cur_idx + arity >= tree_size); + + if (!base_case) + { + for (size_t i = 0; i < arity; ++i) + { + msgs[i] = tree_messages[arity*cur_idx + i + 1]; + proofs[i] = tree_proofs[arity*cur_idx + i + 1]; + } + } + + std::shared_ptr > ld; + ld.reset(new tally_pcd_local_data(tree_elems[cur_idx])); + tally.generate_r1cs_witness(msgs, ld); + + const r1cs_pcd_compliance_predicate_primary_input tally_primary_input(tally.get_outgoing_message()); + const r1cs_pcd_compliance_predicate_auxiliary_input tally_auxiliary_input(msgs, ld, tally.get_witness()); + + print_header("R1CS ppzkPCD Prover"); + r1cs_sp_ppzkpcd_proof proof = r1cs_sp_ppzkpcd_prover(keypair.pk, tally_primary_input, tally_auxiliary_input, proofs); + + if (test_serialization) + { + enter_block("Test serialization of proof"); + proof = reserialize >(proof); + leave_block("Test serialization of proof"); + } + + tree_proofs[cur_idx] = proof; + tree_messages[cur_idx] = tally.get_outgoing_message(); + + print_header("R1CS ppzkPCD Verifier"); + const r1cs_sp_ppzkpcd_primary_input pcd_verifier_input(tree_messages[cur_idx]); + const bool ans = r1cs_sp_ppzkpcd_verifier(keypair.vk, pcd_verifier_input, tree_proofs[cur_idx]); + + print_header("R1CS ppzkPCD Online Verifier"); + const bool ans2 = r1cs_sp_ppzkpcd_online_verifier(pvk, pcd_verifier_input, tree_proofs[cur_idx]); + assert(ans == ans2); + + all_accept = all_accept && ans; + + printf("\n"); + for (size_t i = 0; i < arity; ++i) + { + printf("Message %zu was:\n", i); + msgs[i]->print(); + } + printf("Summand at this node:\n%zu\n", tree_elems[cur_idx]); + printf("Outgoing message is:\n"); + tree_messages[cur_idx]->print(); + printf("\n"); + printf("Current node = %zu. Current proof verifies = %s\n", cur_idx, ans ? "YES" : "NO"); + printf("\n\n\n ================================================================================\n\n\n"); + } + } + + leave_block("Call to run_r1cs_sp_ppzkpcd_tally_example"); + + return all_accept; +} + +} // libsnark + +#endif // RUN_R1CS_SP_PPZKPCD_TCC_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/pcd/r1cs_pcd/r1cs_sp_ppzkpcd/profiling/profile_r1cs_sp_ppzkpcd.cpp b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/pcd/r1cs_pcd/r1cs_sp_ppzkpcd/profiling/profile_r1cs_sp_ppzkpcd.cpp new file mode 100644 index 0000000..0c93394 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/pcd/r1cs_pcd/r1cs_sp_ppzkpcd/profiling/profile_r1cs_sp_ppzkpcd.cpp @@ -0,0 +1,33 @@ +/** + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ +#include "common/default_types/r1cs_ppzkpcd_pp.hpp" +#include "zk_proof_systems/pcd/r1cs_pcd/r1cs_sp_ppzkpcd/r1cs_sp_ppzkpcd.hpp" +#include "zk_proof_systems/pcd/r1cs_pcd/r1cs_sp_ppzkpcd/examples/run_r1cs_sp_ppzkpcd.hpp" + +using namespace libsnark; + +template +void profile_tally(const size_t arity, const size_t max_layer) +{ + const size_t wordsize = 32; + const bool test_serialization = true; + const bool bit = run_r1cs_sp_ppzkpcd_tally_example(wordsize, arity, max_layer, test_serialization); + assert(bit); +} + +int main(void) +{ + typedef default_r1cs_ppzkpcd_pp PCD_pp; + + start_profiling(); + PCD_pp::init_public_params(); + + const size_t arity = 2; + const size_t max_layer = 2; + + profile_tally(arity, max_layer); +} diff --git a/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/pcd/r1cs_pcd/r1cs_sp_ppzkpcd/r1cs_sp_ppzkpcd.hpp b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/pcd/r1cs_pcd/r1cs_sp_ppzkpcd/r1cs_sp_ppzkpcd.hpp new file mode 100644 index 0000000..b7746c1 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/pcd/r1cs_pcd/r1cs_sp_ppzkpcd/r1cs_sp_ppzkpcd.hpp @@ -0,0 +1,308 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for a *single-predicate* ppzkPCD for R1CS. + + This includes: + - class for proving key + - class for verification key + - class for processed verification key + - class for key pair (proving key & verification key) + - class for proof + - generator algorithm + - prover algorithm + - verifier algorithm + - online verifier algorithm + + The implementation follows, extends, and optimizes the approach described + in \[BCTV14]. Thus, PCD is constructed from two "matched" ppzkSNARKs for R1CS. + + Acronyms: + + "R1CS" = "Rank-1 Constraint Systems" + "ppzkSNARK" = "PreProcessing Zero-Knowledge Succinct Non-interactive ARgument of Knowledge" + "ppzkPCD" = "Pre-Processing Zero-Knowledge Proof-Carrying Data" + + References: + + \[BCTV14]: + "Scalable Zero Knowledge via Cycles of Elliptic Curves", + Eli Ben-Sasson, Alessandro Chiesa, Eran Tromer, Madars Virza, + CRYPTO 2014, + + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef R1CS_SP_PPZKPCD_HPP_ +#define R1CS_SP_PPZKPCD_HPP_ + +#include + +#include "zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.hpp" +#include "zk_proof_systems/pcd/r1cs_pcd/r1cs_sp_ppzkpcd/r1cs_sp_ppzkpcd_params.hpp" + +namespace libsnark { + +/******************************** Proving key ********************************/ + +template +class r1cs_sp_ppzkpcd_proving_key; + +template +std::ostream& operator<<(std::ostream &out, const r1cs_sp_ppzkpcd_proving_key &pk); + +template +std::istream& operator>>(std::istream &in, r1cs_sp_ppzkpcd_proving_key &pk); + +/** + * A proving key for the R1CS (single-predicate) ppzkPCD. + */ +template +class r1cs_sp_ppzkpcd_proving_key { +public: + typedef typename PCD_ppT::curve_A_pp A_pp; + typedef typename PCD_ppT::curve_B_pp B_pp; + + r1cs_sp_ppzkpcd_compliance_predicate compliance_predicate; + + r1cs_ppzksnark_proving_key compliance_step_r1cs_pk; + r1cs_ppzksnark_proving_key translation_step_r1cs_pk; + + r1cs_ppzksnark_verification_key compliance_step_r1cs_vk; + r1cs_ppzksnark_verification_key translation_step_r1cs_vk; + + r1cs_sp_ppzkpcd_proving_key() {}; + r1cs_sp_ppzkpcd_proving_key(const r1cs_sp_ppzkpcd_proving_key &other) = default; + r1cs_sp_ppzkpcd_proving_key(r1cs_sp_ppzkpcd_proving_key &&other) = default; + r1cs_sp_ppzkpcd_proving_key(const r1cs_sp_ppzkpcd_compliance_predicate &compliance_predicate, + r1cs_ppzksnark_proving_key &&compliance_step_r1cs_pk, + r1cs_ppzksnark_proving_key &&translation_step_r1cs_pk, + const r1cs_ppzksnark_verification_key &compliance_step_r1cs_vk, + const r1cs_ppzksnark_verification_key &translation_step_r1cs_vk) : + compliance_predicate(compliance_predicate), + compliance_step_r1cs_pk(std::move(compliance_step_r1cs_pk)), + translation_step_r1cs_pk(std::move(translation_step_r1cs_pk)), + compliance_step_r1cs_vk(std::move(compliance_step_r1cs_vk)), + translation_step_r1cs_vk(std::move(translation_step_r1cs_vk)) + {}; + + r1cs_sp_ppzkpcd_proving_key& operator=(const r1cs_sp_ppzkpcd_proving_key &other) = default; + + size_t size_in_bits() const + { + return (compliance_step_r1cs_pk.size_in_bits() + + translation_step_r1cs_pk.size_in_bits() + + compliance_step_r1cs_vk.size_in_bits() + + translation_step_r1cs_vk.size_in_bits()); + } + + bool operator==(const r1cs_sp_ppzkpcd_proving_key &other) const; + friend std::ostream& operator<< (std::ostream &out, const r1cs_sp_ppzkpcd_proving_key &pk); + friend std::istream& operator>> (std::istream &in, r1cs_sp_ppzkpcd_proving_key &pk); +}; + + +/******************************* Verification key ****************************/ + +template +class r1cs_sp_ppzkpcd_verification_key; + +template +std::ostream& operator<<(std::ostream &out, const r1cs_sp_ppzkpcd_verification_key &vk); + +template +std::istream& operator>>(std::istream &in, r1cs_sp_ppzkpcd_verification_key &vk); + +/** + * A verification key for the R1CS (single-predicate) ppzkPCD. + */ +template +class r1cs_sp_ppzkpcd_verification_key { +public: + typedef typename PCD_ppT::curve_A_pp A_pp; + typedef typename PCD_ppT::curve_B_pp B_pp; + + r1cs_ppzksnark_verification_key compliance_step_r1cs_vk; + r1cs_ppzksnark_verification_key translation_step_r1cs_vk; + + r1cs_sp_ppzkpcd_verification_key() = default; + r1cs_sp_ppzkpcd_verification_key(const r1cs_sp_ppzkpcd_verification_key &other) = default; + r1cs_sp_ppzkpcd_verification_key(r1cs_sp_ppzkpcd_verification_key &&other) = default; + r1cs_sp_ppzkpcd_verification_key(const r1cs_ppzksnark_verification_key &compliance_step_r1cs_vk, + const r1cs_ppzksnark_verification_key &translation_step_r1cs_vk) : + compliance_step_r1cs_vk(std::move(compliance_step_r1cs_vk)), + translation_step_r1cs_vk(std::move(translation_step_r1cs_vk)) + {}; + + r1cs_sp_ppzkpcd_verification_key& operator=(const r1cs_sp_ppzkpcd_verification_key &other) = default; + + size_t size_in_bits() const + { + return (compliance_step_r1cs_vk.size_in_bits() + + translation_step_r1cs_vk.size_in_bits()); + } + + bool operator==(const r1cs_sp_ppzkpcd_verification_key &other) const; + friend std::ostream& operator<< (std::ostream &out, const r1cs_sp_ppzkpcd_verification_key &vk); + friend std::istream& operator>> (std::istream &in, r1cs_sp_ppzkpcd_verification_key &vk); + + static r1cs_sp_ppzkpcd_verification_key dummy_verification_key(); +}; + + +/************************ Processed verification key *************************/ + +template +class r1cs_sp_ppzkpcd_processed_verification_key; + +template +std::ostream& operator<<(std::ostream &out, const r1cs_sp_ppzkpcd_processed_verification_key &pvk); + +template +std::istream& operator>>(std::istream &in, r1cs_sp_ppzkpcd_processed_verification_key &pvk); + +/** + * A processed verification key for the R1CS (single-predicate) ppzkPCD. + * + * Compared to a (non-processed) verification key, a processed verification key + * contains a small constant amount of additional pre-computed information that + * enables a faster verification time. + */ +template +class r1cs_sp_ppzkpcd_processed_verification_key { +public: + typedef typename PCD_ppT::curve_A_pp A_pp; + typedef typename PCD_ppT::curve_B_pp B_pp; + + r1cs_ppzksnark_processed_verification_key compliance_step_r1cs_pvk; + r1cs_ppzksnark_processed_verification_key translation_step_r1cs_pvk; + bit_vector translation_step_r1cs_vk_bits; + + r1cs_sp_ppzkpcd_processed_verification_key() {}; + r1cs_sp_ppzkpcd_processed_verification_key(const r1cs_sp_ppzkpcd_processed_verification_key &other) = default; + r1cs_sp_ppzkpcd_processed_verification_key(r1cs_sp_ppzkpcd_processed_verification_key &&other) = default; + r1cs_sp_ppzkpcd_processed_verification_key(r1cs_ppzksnark_processed_verification_key &&compliance_step_r1cs_pvk, + r1cs_ppzksnark_processed_verification_key &&translation_step_r1cs_pvk, + const bit_vector &translation_step_r1cs_vk_bits) : + compliance_step_r1cs_pvk(std::move(compliance_step_r1cs_pvk)), + translation_step_r1cs_pvk(std::move(translation_step_r1cs_pvk)), + translation_step_r1cs_vk_bits(std::move(translation_step_r1cs_vk_bits)) + {}; + + r1cs_sp_ppzkpcd_processed_verification_key& operator=(const r1cs_sp_ppzkpcd_processed_verification_key &other) = default; + + size_t size_in_bits() const + { + return (compliance_step_r1cs_pvk.size_in_bits() + + translation_step_r1cs_pvk.size_in_bits() + + translation_step_r1cs_vk_bits.size()); + } + + bool operator==(const r1cs_sp_ppzkpcd_processed_verification_key &other) const; + friend std::ostream& operator<< (std::ostream &out, const r1cs_sp_ppzkpcd_processed_verification_key &pvk); + friend std::istream& operator>> (std::istream &in, r1cs_sp_ppzkpcd_processed_verification_key &pvk); +}; + + +/********************************* Key pair **********************************/ + +/** + * A key pair for the R1CS (single-predicate) ppzkPC, which consists of a proving key and a verification key. + */ +template +class r1cs_sp_ppzkpcd_keypair { +public: + typedef typename PCD_ppT::curve_A_pp A_pp; + typedef typename PCD_ppT::curve_B_pp B_pp; + + r1cs_sp_ppzkpcd_proving_key pk; + r1cs_sp_ppzkpcd_verification_key vk; + + r1cs_sp_ppzkpcd_keypair() {}; + r1cs_sp_ppzkpcd_keypair(r1cs_sp_ppzkpcd_keypair &&other) = default; + r1cs_sp_ppzkpcd_keypair(r1cs_sp_ppzkpcd_proving_key &&pk, + r1cs_sp_ppzkpcd_verification_key &&vk) : + pk(std::move(pk)), + vk(std::move(vk)) + {}; + r1cs_sp_ppzkpcd_keypair(r1cs_ppzksnark_keypair &&kp_A, + r1cs_ppzksnark_keypair &&kp_B) : + pk(std::move(kp_A.pk),std::move(kp_B.pk)), + vk(std::move(kp_A.vk),std::move(kp_B.vk)) + {}; +}; + + +/*********************************** Proof ***********************************/ + +/** + * A proof for the R1CS (single-predicate) ppzkPCD. + */ +template +using r1cs_sp_ppzkpcd_proof = r1cs_ppzksnark_proof; + + +/***************************** Main algorithms *******************************/ + +/** + * A generator algorithm for the R1CS (single-predicate) ppzkPCD. + * + * Given a compliance predicate, this algorithm produces proving and verification keys for the predicate. + */ +template +r1cs_sp_ppzkpcd_keypair r1cs_sp_ppzkpcd_generator(const r1cs_sp_ppzkpcd_compliance_predicate &compliance_predicate); + +/** + * A prover algorithm for the R1CS (single-predicate) ppzkPCD. + * + * Given a proving key, inputs for the compliance predicate, and proofs for + * the predicate's input messages, this algorithm produces a proof (of knowledge) + * that attests to the compliance of the output message. + */ +template +r1cs_sp_ppzkpcd_proof r1cs_sp_ppzkpcd_prover(const r1cs_sp_ppzkpcd_proving_key &pk, + const r1cs_sp_ppzkpcd_primary_input &primary_input, + const r1cs_sp_ppzkpcd_auxiliary_input &auxiliary_input, + const std::vector > &incoming_proofs); + +/* + Below are two variants of verifier algorithm for the R1CS (single-predicate) ppzkPCD. + + These are the two cases that arise from whether the verifier accepts a + (non-processed) verification key or, instead, a processed verification key. + In the latter case, we call the algorithm an "online verifier". + */ + +/** + * A verifier algorithm for the R1CS (single-predicate) ppzkPCD that + * accepts a non-processed verification key. + */ +template +bool r1cs_sp_ppzkpcd_verifier(const r1cs_sp_ppzkpcd_verification_key &vk, + const r1cs_sp_ppzkpcd_primary_input &primary_input, + const r1cs_sp_ppzkpcd_proof &proof); + +/** + * Convert a (non-processed) verification key into a processed verification key. + */ +template +r1cs_sp_ppzkpcd_processed_verification_key r1cs_sp_ppzkpcd_process_vk(const r1cs_sp_ppzkpcd_verification_key &vk); + +/** + * A verifier algorithm for the R1CS (single-predicate) ppzkPCD that + * accepts a processed verification key. + */ +template +bool r1cs_sp_ppzkpcd_online_verifier(const r1cs_sp_ppzkpcd_processed_verification_key &pvk, + const r1cs_sp_ppzkpcd_primary_input &primary_input, + const r1cs_sp_ppzkpcd_proof &proof); + +} // libsnark + +#include "zk_proof_systems/pcd/r1cs_pcd/r1cs_sp_ppzkpcd/r1cs_sp_ppzkpcd.tcc" + +#endif // R1CS_SP_PPZKPCD_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/pcd/r1cs_pcd/r1cs_sp_ppzkpcd/r1cs_sp_ppzkpcd.tcc b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/pcd/r1cs_pcd/r1cs_sp_ppzkpcd/r1cs_sp_ppzkpcd.tcc new file mode 100644 index 0000000..e284819 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/pcd/r1cs_pcd/r1cs_sp_ppzkpcd/r1cs_sp_ppzkpcd.tcc @@ -0,0 +1,289 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for a *single-predicate* ppzkPCD for R1CS. + + See r1cs_sp_ppzkpcd.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef R1CS_SP_PPZKPCD_TCC_ +#define R1CS_SP_PPZKPCD_TCC_ + +#include +#include +#include + +#include "common/profiling.hpp" +#include "common/utils.hpp" +#include "zk_proof_systems/pcd/r1cs_pcd/r1cs_sp_ppzkpcd/sp_pcd_circuits.hpp" + +namespace libsnark { + +template +bool r1cs_sp_ppzkpcd_proving_key::operator==(const r1cs_sp_ppzkpcd_proving_key &other) const +{ + return (this->compliance_predicate == other.compliance_predicate && + this->compliance_step_r1cs_pk == other.compliance_step_r1cs_pk && + this->translation_step_r1cs_pk == other.translation_step_r1cs_pk && + this->compliance_step_r1cs_vk == other.compliance_step_r1cs_vk && + this->translation_step_r1cs_vk == other.translation_step_r1cs_vk); +} + +template +std::ostream& operator<<(std::ostream &out, const r1cs_sp_ppzkpcd_proving_key &pk) +{ + out << pk.compliance_predicate; + out << pk.compliance_step_r1cs_pk; + out << pk.translation_step_r1cs_pk; + out << pk.compliance_step_r1cs_vk; + out << pk.translation_step_r1cs_vk; + + return out; +} + +template +std::istream& operator>>(std::istream &in, r1cs_sp_ppzkpcd_proving_key &pk) +{ + in >> pk.compliance_predicate; + in >> pk.compliance_step_r1cs_pk; + in >> pk.translation_step_r1cs_pk; + in >> pk.compliance_step_r1cs_vk; + in >> pk.translation_step_r1cs_vk; + + return in; +} + +template +bool r1cs_sp_ppzkpcd_verification_key::operator==(const r1cs_sp_ppzkpcd_verification_key &other) const +{ + return (this->compliance_step_r1cs_vk == other.compliance_step_r1cs_vk && + this->translation_step_r1cs_vk == other.translation_step_r1cs_vk); +} + +template +std::ostream& operator<<(std::ostream &out, const r1cs_sp_ppzkpcd_verification_key &vk) +{ + out << vk.compliance_step_r1cs_vk; + out << vk.translation_step_r1cs_vk; + + return out; +} + +template +std::istream& operator>>(std::istream &in, r1cs_sp_ppzkpcd_verification_key &vk) +{ + in >> vk.compliance_step_r1cs_vk; + in >> vk.translation_step_r1cs_vk; + + return in; +} + +template +r1cs_sp_ppzkpcd_verification_key r1cs_sp_ppzkpcd_verification_key::dummy_verification_key() +{ + typedef typename PCD_ppT::curve_A_pp curve_A_pp; + typedef typename PCD_ppT::curve_B_pp curve_B_pp; + + r1cs_sp_ppzkpcd_verification_key result; + result.compliance_step_r1cs_vk = r1cs_ppzksnark_verification_key::dummy_verification_key(sp_compliance_step_pcd_circuit_maker::input_size_in_elts()); + result.translation_step_r1cs_vk = r1cs_ppzksnark_verification_key::dummy_verification_key(sp_translation_step_pcd_circuit_maker::input_size_in_elts()); + + return result; +} + +template +bool r1cs_sp_ppzkpcd_processed_verification_key::operator==(const r1cs_sp_ppzkpcd_processed_verification_key &other) const +{ + return (this->compliance_step_r1cs_pvk == other.compliance_step_r1cs_pvk && + this->translation_step_r1cs_pvk == other.translation_step_r1cs_pvk && + this->translation_step_r1cs_vk_bits == other.translation_step_r1cs_vk_bits); +} + +template +std::ostream& operator<<(std::ostream &out, const r1cs_sp_ppzkpcd_processed_verification_key &pvk) +{ + out << pvk.compliance_step_r1cs_pvk; + out << pvk.translation_step_r1cs_pvk; + serialize_bit_vector(out, pvk.translation_step_r1cs_vk_bits); + + return out; +} + +template +std::istream& operator>>(std::istream &in, r1cs_sp_ppzkpcd_processed_verification_key &pvk) +{ + in >> pvk.compliance_step_r1cs_pvk; + in >> pvk.translation_step_r1cs_pvk; + deserialize_bit_vector(in, pvk.translation_step_r1cs_vk_bits); + + return in; +} + +template +r1cs_sp_ppzkpcd_keypair r1cs_sp_ppzkpcd_generator(const r1cs_sp_ppzkpcd_compliance_predicate &compliance_predicate) +{ + assert(Fr::mod == Fq::mod); + assert(Fq::mod == Fr::mod); + + typedef Fr FieldT_A; + typedef Fr FieldT_B; + + typedef typename PCD_ppT::curve_A_pp curve_A_pp; + typedef typename PCD_ppT::curve_B_pp curve_B_pp; + + enter_block("Call to r1cs_sp_ppzkpcd_generator"); + + assert(compliance_predicate.is_well_formed()); + + enter_block("Construct compliance step PCD circuit"); + sp_compliance_step_pcd_circuit_maker compliance_step_pcd_circuit(compliance_predicate); + compliance_step_pcd_circuit.generate_r1cs_constraints(); + const r1cs_constraint_system compliance_step_pcd_circuit_cs = compliance_step_pcd_circuit.get_circuit(); + compliance_step_pcd_circuit_cs.report_linear_constraint_statistics(); + leave_block("Construct compliance step PCD circuit"); + + enter_block("Generate key pair for compliance step PCD circuit"); + r1cs_ppzksnark_keypair compliance_step_keypair = r1cs_ppzksnark_generator(compliance_step_pcd_circuit_cs); + leave_block("Generate key pair for compliance step PCD circuit"); + + enter_block("Construct translation step PCD circuit"); + sp_translation_step_pcd_circuit_maker translation_step_pcd_circuit(compliance_step_keypair.vk); + translation_step_pcd_circuit.generate_r1cs_constraints(); + const r1cs_constraint_system translation_step_pcd_circuit_cs = translation_step_pcd_circuit.get_circuit(); + translation_step_pcd_circuit_cs.report_linear_constraint_statistics(); + leave_block("Construct translation step PCD circuit"); + + enter_block("Generate key pair for translation step PCD circuit"); + r1cs_ppzksnark_keypair translation_step_keypair = r1cs_ppzksnark_generator(translation_step_pcd_circuit_cs); + leave_block("Generate key pair for translation step PCD circuit"); + + print_indent(); print_mem("in generator"); + leave_block("Call to r1cs_sp_ppzkpcd_generator"); + + return r1cs_sp_ppzkpcd_keypair(r1cs_sp_ppzkpcd_proving_key(compliance_predicate, + std::move(compliance_step_keypair.pk), + std::move(translation_step_keypair.pk), + compliance_step_keypair.vk, + translation_step_keypair.vk), + r1cs_sp_ppzkpcd_verification_key(compliance_step_keypair.vk, + translation_step_keypair.vk)); +} + +template +r1cs_sp_ppzkpcd_proof r1cs_sp_ppzkpcd_prover(const r1cs_sp_ppzkpcd_proving_key &pk, + const r1cs_sp_ppzkpcd_primary_input &primary_input, + const r1cs_sp_ppzkpcd_auxiliary_input &auxiliary_input, + const std::vector > &incoming_proofs) +{ + typedef Fr FieldT_A; + typedef Fr FieldT_B; + + typedef typename PCD_ppT::curve_A_pp curve_A_pp; + typedef typename PCD_ppT::curve_B_pp curve_B_pp; + + enter_block("Call to r1cs_sp_ppzkpcd_prover"); + + const bit_vector translation_step_r1cs_vk_bits = r1cs_ppzksnark_verification_key_variable::get_verification_key_bits(pk.translation_step_r1cs_vk); +#ifdef DEBUG + printf("Outgoing message:\n"); + primary_input.outgoing_message->print(); +#endif + + enter_block("Prove compliance step"); + sp_compliance_step_pcd_circuit_maker compliance_step_pcd_circuit(pk.compliance_predicate); + compliance_step_pcd_circuit.generate_r1cs_witness(pk.translation_step_r1cs_vk, + primary_input, + auxiliary_input, + incoming_proofs); + + const r1cs_primary_input compliance_step_primary_input = compliance_step_pcd_circuit.get_primary_input(); + const r1cs_auxiliary_input compliance_step_auxiliary_input = compliance_step_pcd_circuit.get_auxiliary_input(); + + const r1cs_ppzksnark_proof compliance_step_proof = r1cs_ppzksnark_prover(pk.compliance_step_r1cs_pk, compliance_step_primary_input, compliance_step_auxiliary_input); + leave_block("Prove compliance step"); + +#ifdef DEBUG + const r1cs_primary_input compliance_step_input = get_sp_compliance_step_pcd_circuit_input(translation_step_r1cs_vk_bits, primary_input); + const bool compliance_step_ok = r1cs_ppzksnark_verifier_strong_IC(pk.compliance_step_r1cs_vk, compliance_step_input, compliance_step_proof); + assert(compliance_step_ok); +#endif + + enter_block("Prove translation step"); + sp_translation_step_pcd_circuit_maker translation_step_pcd_circuit(pk.compliance_step_r1cs_vk); + + const r1cs_primary_input translation_step_primary_input = get_sp_translation_step_pcd_circuit_input(translation_step_r1cs_vk_bits, primary_input); + translation_step_pcd_circuit.generate_r1cs_witness(translation_step_primary_input, compliance_step_proof); // TODO: potential for better naming + + const r1cs_auxiliary_input translation_step_auxiliary_input = translation_step_pcd_circuit.get_auxiliary_input(); + const r1cs_ppzksnark_proof translation_step_proof = r1cs_ppzksnark_prover(pk.translation_step_r1cs_pk, translation_step_primary_input, translation_step_auxiliary_input); + leave_block("Prove translation step"); + +#ifdef DEBUG + const bool translation_step_ok = r1cs_ppzksnark_verifier_strong_IC(pk.translation_step_r1cs_vk, translation_step_primary_input, translation_step_proof); + assert(translation_step_ok); +#endif + + print_indent(); print_mem("in prover"); + leave_block("Call to r1cs_sp_ppzkpcd_prover"); + + return translation_step_proof; +} + +template +bool r1cs_sp_ppzkpcd_online_verifier(const r1cs_sp_ppzkpcd_processed_verification_key &pvk, + const r1cs_sp_ppzkpcd_primary_input &primary_input, + const r1cs_sp_ppzkpcd_proof &proof) + +{ + typedef typename PCD_ppT::curve_B_pp curve_B_pp; + + enter_block("Call to r1cs_sp_ppzkpcd_online_verifier"); + const r1cs_primary_input > r1cs_input = get_sp_translation_step_pcd_circuit_input(pvk.translation_step_r1cs_vk_bits, primary_input); + const bool result = r1cs_ppzksnark_online_verifier_strong_IC(pvk.translation_step_r1cs_pvk, r1cs_input, proof); + print_indent(); print_mem("in online verifier"); + leave_block("Call to r1cs_sp_ppzkpcd_online_verifier"); + + return result; +} + +template +r1cs_sp_ppzkpcd_processed_verification_key r1cs_sp_ppzkpcd_process_vk(const r1cs_sp_ppzkpcd_verification_key &vk) +{ + typedef typename PCD_ppT::curve_A_pp curve_A_pp; + typedef typename PCD_ppT::curve_B_pp curve_B_pp; + + enter_block("Call to r1cs_sp_ppzkpcd_processed_verification_key"); + r1cs_ppzksnark_processed_verification_key compliance_step_r1cs_pvk = r1cs_ppzksnark_verifier_process_vk(vk.compliance_step_r1cs_vk); + r1cs_ppzksnark_processed_verification_key translation_step_r1cs_pvk = r1cs_ppzksnark_verifier_process_vk(vk.translation_step_r1cs_vk); + const bit_vector translation_step_r1cs_vk_bits = r1cs_ppzksnark_verification_key_variable::get_verification_key_bits(vk.translation_step_r1cs_vk); + leave_block("Call to r1cs_sp_ppzkpcd_processed_verification_key"); + + return r1cs_sp_ppzkpcd_processed_verification_key(std::move(compliance_step_r1cs_pvk), + std::move(translation_step_r1cs_pvk), + translation_step_r1cs_vk_bits); +} + + +template +bool r1cs_sp_ppzkpcd_verifier(const r1cs_sp_ppzkpcd_verification_key &vk, + const r1cs_sp_ppzkpcd_primary_input &primary_input, + const r1cs_sp_ppzkpcd_proof &proof) +{ + enter_block("Call to r1cs_sp_ppzkpcd_verifier"); + const r1cs_sp_ppzkpcd_processed_verification_key pvk = r1cs_sp_ppzkpcd_process_vk(vk); + const bool result = r1cs_sp_ppzkpcd_online_verifier(pvk, primary_input, proof); + print_indent(); print_mem("in verifier"); + leave_block("Call to r1cs_sp_ppzkpcd_verifier"); + + return result; +} + + +} // libsnark + +#endif // R1CS_SP_PPZKPCD_TCC_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/pcd/r1cs_pcd/r1cs_sp_ppzkpcd/r1cs_sp_ppzkpcd_params.hpp b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/pcd/r1cs_pcd/r1cs_sp_ppzkpcd/r1cs_sp_ppzkpcd_params.hpp new file mode 100644 index 0000000..16d41a8 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/pcd/r1cs_pcd/r1cs_sp_ppzkpcd/r1cs_sp_ppzkpcd_params.hpp @@ -0,0 +1,38 @@ +/** @file + ***************************************************************************** + + Parameters for *single-predicate* ppzkPCD for R1CS. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef R1CS_SP_PPZKPCD_PARAMS_HPP_ +#define R1CS_SP_PPZKPCD_PARAMS_HPP_ + +#include "algebra/curves/public_params.hpp" +#include "zk_proof_systems/pcd/r1cs_pcd/compliance_predicate/compliance_predicate.hpp" +#include "zk_proof_systems/pcd/r1cs_pcd/r1cs_pcd_params.hpp" + +namespace libsnark { + +template +using r1cs_sp_ppzkpcd_compliance_predicate = r1cs_pcd_compliance_predicate >; + +template +using r1cs_sp_ppzkpcd_message = r1cs_pcd_message >; + +template +using r1cs_sp_ppzkpcd_local_data = r1cs_pcd_local_data >; + +template +using r1cs_sp_ppzkpcd_primary_input = r1cs_pcd_compliance_predicate_primary_input >; + +template +using r1cs_sp_ppzkpcd_auxiliary_input = r1cs_pcd_compliance_predicate_auxiliary_input >; + +} // libsnark + +#endif // R1CS_SP_PPZKPCD_PARAMS_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/pcd/r1cs_pcd/r1cs_sp_ppzkpcd/sp_pcd_circuits.hpp b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/pcd/r1cs_pcd/r1cs_sp_ppzkpcd/sp_pcd_circuits.hpp new file mode 100644 index 0000000..ee7d9c2 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/pcd/r1cs_pcd/r1cs_sp_ppzkpcd/sp_pcd_circuits.hpp @@ -0,0 +1,174 @@ +/** @file + ***************************************************************************** + + Declaration of functionality for creating and using the two PCD circuits in + a single-predicate PCD construction. + + The implementation follows, extends, and optimizes the approach described + in \[BCTV14]. At high level, there is a "compliance step" circuit and a + "translation step" circuit. For more details see Section 4 of \[BCTV14]. + + + References: + + \[BCTV14]: + "Scalable Zero Knowledge via Cycles of Elliptic Curves", + Eli Ben-Sasson, Alessandro Chiesa, Eran Tromer, Madars Virza, + CRYPTO 2014, + + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef SP_PCD_CIRCUITS_HPP_ +#define SP_PCD_CIRCUITS_HPP_ + +#include "gadgetlib1/protoboard.hpp" +#include "gadgetlib1/gadgets/gadget_from_r1cs.hpp" +#include "gadgetlib1/gadgets/hashes/crh_gadget.hpp" +#include "gadgetlib1/gadgets/pairing/pairing_params.hpp" +#include "gadgetlib1/gadgets/verifiers/r1cs_ppzksnark_verifier_gadget.hpp" +#include "zk_proof_systems/pcd/r1cs_pcd/compliance_predicate/cp_handler.hpp" + +namespace libsnark { + +/**************************** Compliance step ********************************/ + +/** + * A compliance-step PCD circuit. + * + * The circuit is an R1CS that checks compliance (for the given compliance predicate) + * and validity of previous proofs. + */ +template +class sp_compliance_step_pcd_circuit_maker { +public: + typedef Fr FieldT; + + r1cs_pcd_compliance_predicate compliance_predicate; + + protoboard pb; + + pb_variable zero; + + std::shared_ptr > block_for_outgoing_message; + std::shared_ptr > hash_outgoing_message; + + std::vector > blocks_for_incoming_messages; + std::vector > sp_translation_step_vk_and_incoming_message_payload_digests; + std::vector > unpack_sp_translation_step_vk_and_incoming_message_payload_digests; + std::vector > sp_translation_step_vk_and_incoming_message_payload_digest_bits; + std::vector > hash_incoming_messages; + + std::shared_ptr > sp_translation_step_vk; + pb_variable_array sp_translation_step_vk_bits; + + pb_variable outgoing_message_type; + pb_variable_array outgoing_message_payload; + pb_variable_array outgoing_message_vars; + + pb_variable arity; + std::vector > incoming_message_types; + std::vector > incoming_message_payloads; + std::vector > incoming_message_vars; + + pb_variable_array local_data; + pb_variable_array cp_witness; + std::shared_ptr > compliance_predicate_as_gadget; + + pb_variable_array outgoing_message_bits; + std::shared_ptr > unpack_outgoing_message; + + std::vector > incoming_messages_bits; + std::vector > unpack_incoming_messages; + + pb_variable_array sp_compliance_step_pcd_circuit_input; + pb_variable_array padded_translation_step_vk_and_outgoing_message_digest; + std::vector > padded_translation_step_vk_and_incoming_messages_digests; + + std::vector > verifier_input; + std::vector > proof; + pb_variable verification_result; + std::vector > verifiers; + + sp_compliance_step_pcd_circuit_maker(const r1cs_pcd_compliance_predicate &compliance_predicate); + void generate_r1cs_constraints(); + r1cs_constraint_system get_circuit() const; + + void generate_r1cs_witness(const r1cs_ppzksnark_verification_key > &translation_step_pcd_circuit_vk, + const r1cs_pcd_compliance_predicate_primary_input &compliance_predicate_primary_input, + const r1cs_pcd_compliance_predicate_auxiliary_input &compliance_predicate_auxiliary_input, + const std::vector > > &incoming_proofs); + r1cs_primary_input get_primary_input() const; + r1cs_auxiliary_input get_auxiliary_input() const; + + static size_t field_logsize(); + static size_t field_capacity(); + static size_t input_size_in_elts(); + static size_t input_capacity_in_bits(); + static size_t input_size_in_bits(); +}; + +/*************************** Translation step ********************************/ + +/** + * A translation-step PCD circuit. + * + * The circuit is an R1CS that checks validity of previous proofs. + */ +template +class sp_translation_step_pcd_circuit_maker { +public: + typedef Fr FieldT; + + protoboard pb; + + pb_variable_array sp_translation_step_pcd_circuit_input; + pb_variable_array unpacked_sp_translation_step_pcd_circuit_input; + pb_variable_array verifier_input; + std::shared_ptr > unpack_sp_translation_step_pcd_circuit_input; + + std::shared_ptr > hardcoded_sp_compliance_step_vk; + std::shared_ptr > proof; + std::shared_ptr > online_verifier; + + sp_translation_step_pcd_circuit_maker(const r1cs_ppzksnark_verification_key > &compliance_step_vk); + void generate_r1cs_constraints(); + r1cs_constraint_system get_circuit() const; + + void generate_r1cs_witness(const r1cs_primary_input > translation_step_input, + const r1cs_ppzksnark_proof > &compliance_step_proof); + r1cs_primary_input get_primary_input() const; + r1cs_auxiliary_input get_auxiliary_input() const; + + static size_t field_logsize(); + static size_t field_capacity(); + static size_t input_size_in_elts(); + static size_t input_capacity_in_bits(); + static size_t input_size_in_bits(); +}; + +/****************************** Input maps ***********************************/ + +/** + * Obtain the primary input for a compliance-step PCD circuit. + */ +template +r1cs_primary_input > get_sp_compliance_step_pcd_circuit_input(const bit_vector &sp_translation_step_vk_bits, + const r1cs_pcd_compliance_predicate_primary_input > &primary_input); + +/** + * Obtain the primary input for a translation-step PCD circuit. + */ +template +r1cs_primary_input > get_sp_translation_step_pcd_circuit_input(const bit_vector &sp_translation_step_vk_bits, + const r1cs_pcd_compliance_predicate_primary_input > > &primary_input); + +} // libsnark + +#include "zk_proof_systems/pcd/r1cs_pcd/r1cs_sp_ppzkpcd/sp_pcd_circuits.tcc" + +#endif // SP_PCD_CIRCUITS_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/pcd/r1cs_pcd/r1cs_sp_ppzkpcd/sp_pcd_circuits.tcc b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/pcd/r1cs_pcd/r1cs_sp_ppzkpcd/sp_pcd_circuits.tcc new file mode 100644 index 0000000..7a607dc --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/pcd/r1cs_pcd/r1cs_sp_ppzkpcd/sp_pcd_circuits.tcc @@ -0,0 +1,529 @@ +/** @file + ***************************************************************************** + + Implementation of functionality for creating and using the two PCD circuits in + a single-predicate PCD construction. + + See sp_pcd_circuits.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef SP_PCD_CIRCUITS_TCC_ +#define SP_PCD_CIRCUITS_TCC_ + +#include "common/utils.hpp" +#include "gadgetlib1/constraint_profiling.hpp" + +namespace libsnark { + +template +sp_compliance_step_pcd_circuit_maker::sp_compliance_step_pcd_circuit_maker(const r1cs_pcd_compliance_predicate &compliance_predicate) : + compliance_predicate(compliance_predicate) +{ + /* calculate some useful sizes */ + assert(compliance_predicate.is_well_formed()); + assert(compliance_predicate.has_equal_input_and_output_lengths()); + + const size_t compliance_predicate_arity = compliance_predicate.max_arity; + const size_t digest_size = CRH_with_field_out_gadget::get_digest_len(); + const size_t msg_size_in_bits = field_logsize() * (1+compliance_predicate.outgoing_message_payload_length); + const size_t sp_translation_step_vk_size_in_bits = r1cs_ppzksnark_verification_key_variable::size_in_bits(sp_translation_step_pcd_circuit_maker >::input_size_in_elts()); + const size_t padded_verifier_input_size = sp_translation_step_pcd_circuit_maker >::input_capacity_in_bits(); + + printf("other curve input size = %zu\n", sp_translation_step_pcd_circuit_maker >::input_size_in_elts()); + printf("translation_vk_bits = %zu\n", sp_translation_step_vk_size_in_bits); + printf("padded verifier input size = %zu\n", padded_verifier_input_size); + + const size_t block_size = msg_size_in_bits + sp_translation_step_vk_size_in_bits; + CRH_with_bit_out_gadget::sample_randomness(block_size); + + /* allocate input of the compliance PCD circuit */ + sp_compliance_step_pcd_circuit_input.allocate(pb, input_size_in_elts(), "sp_compliance_step_pcd_circuit_input"); + + /* allocate inputs to the compliance predicate */ + outgoing_message_type.allocate(pb, "outgoing_message_type"); + outgoing_message_payload.allocate(pb, compliance_predicate.outgoing_message_payload_length, "outgoing_message_payload"); + + outgoing_message_vars.insert(outgoing_message_vars.end(), outgoing_message_type); + outgoing_message_vars.insert(outgoing_message_vars.end(), outgoing_message_payload.begin(), outgoing_message_payload.end()); + + arity.allocate(pb, "arity"); + + incoming_message_types.resize(compliance_predicate_arity); + incoming_message_payloads.resize(compliance_predicate_arity); + incoming_message_vars.resize(compliance_predicate_arity); + for (size_t i = 0; i < compliance_predicate_arity; ++i) + { + incoming_message_types[i].allocate(pb, FMT("", "incoming_message_type_%zu", i)); + incoming_message_payloads[i].allocate(pb, compliance_predicate.outgoing_message_payload_length, FMT("", "incoming_message_payloads_%zu", i)); + + incoming_message_vars[i].insert(incoming_message_vars[i].end(), incoming_message_types[i]); + incoming_message_vars[i].insert(incoming_message_vars[i].end(), incoming_message_payloads[i].begin(), incoming_message_payloads[i].end()); + } + + local_data.allocate(pb, compliance_predicate.local_data_length, "local_data"); + cp_witness.allocate(pb, compliance_predicate.witness_length, "cp_witness"); + + /* convert compliance predicate from a constraint system into a gadget */ + pb_variable_array incoming_messages_concat; + for (size_t i = 0; i < compliance_predicate_arity; ++i) + { + incoming_messages_concat.insert(incoming_messages_concat.end(), incoming_message_vars[i].begin(), incoming_message_vars[i].end()); + } + + compliance_predicate_as_gadget.reset(new gadget_from_r1cs(pb, + { outgoing_message_vars, + pb_variable_array(1, arity), + incoming_messages_concat, + local_data, + cp_witness }, + compliance_predicate.constraint_system, "compliance_predicate_as_gadget")); + + /* unpack messages to bits */ + outgoing_message_bits.allocate(pb, msg_size_in_bits, "outgoing_message_bits"); + unpack_outgoing_message.reset(new multipacking_gadget(pb, outgoing_message_bits, outgoing_message_vars, field_logsize(), "unpack_outgoing_message")); + + incoming_messages_bits.resize(compliance_predicate_arity); + for (size_t i = 0; i < compliance_predicate_arity; ++i) + { + incoming_messages_bits[i].allocate(pb, msg_size_in_bits, FMT("", "incoming_messages_bits_%zu", i)); + unpack_incoming_messages.emplace_back(multipacking_gadget(pb, incoming_messages_bits[i], incoming_message_vars[i], field_logsize(), FMT("", "unpack_incoming_messages_%zu", i))); + } + + /* allocate digests */ + sp_translation_step_vk_and_incoming_message_payload_digests.resize(compliance_predicate_arity); + for (size_t i = 0; i < compliance_predicate_arity; ++i) + { + sp_translation_step_vk_and_incoming_message_payload_digests[i].allocate(pb, digest_size, FMT("", "sp_translation_step_vk_and_incoming_message_payload_digests_%zu", i)); + } + + /* allocate blocks */ + sp_translation_step_vk_bits.allocate(pb, sp_translation_step_vk_size_in_bits, "sp_translation_step_vk_bits"); + + block_for_outgoing_message.reset(new block_variable(pb, { + sp_translation_step_vk_bits, + outgoing_message_bits }, "block_for_outgoing_message")); + + for (size_t i = 0; i < compliance_predicate_arity; ++i) + { + blocks_for_incoming_messages.emplace_back(block_variable(pb, { + sp_translation_step_vk_bits, + incoming_messages_bits[i] }, FMT("", "blocks_for_incoming_messages_zu", i))); + } + + /* allocate hash checkers */ + hash_outgoing_message.reset(new CRH_with_field_out_gadget(pb, block_size, *block_for_outgoing_message, sp_compliance_step_pcd_circuit_input, "hash_outgoing_message")); + + for (size_t i = 0; i < compliance_predicate_arity; ++i) + { + hash_incoming_messages.emplace_back(CRH_with_field_out_gadget(pb, block_size, blocks_for_incoming_messages[i], sp_translation_step_vk_and_incoming_message_payload_digests[i], FMT("", "hash_incoming_messages_%zu", i))); + } + + /* allocate useful zero variable */ + zero.allocate(pb, "zero"); + + /* prepare arguments for the verifier */ + sp_translation_step_vk.reset(new r1cs_ppzksnark_verification_key_variable(pb, sp_translation_step_vk_bits, sp_translation_step_pcd_circuit_maker >::input_size_in_elts(), "sp_translation_step_vk")); + + verification_result.allocate(pb, "verification_result"); + sp_translation_step_vk_and_incoming_message_payload_digest_bits.resize(compliance_predicate_arity); + + for (size_t i = 0; i < compliance_predicate_arity; ++i) + { + sp_translation_step_vk_and_incoming_message_payload_digest_bits[i].allocate(pb, digest_size * field_logsize(), FMT("", "sp_translation_step_vk_and_incoming_message_payload_digest_bits_%zu", i)); + unpack_sp_translation_step_vk_and_incoming_message_payload_digests.emplace_back(multipacking_gadget(pb, + sp_translation_step_vk_and_incoming_message_payload_digest_bits[i], + sp_translation_step_vk_and_incoming_message_payload_digests[i], + field_logsize(), + FMT("", "unpack_sp_translation_step_vk_and_incoming_message_payload_digests_%zu", i))); + + verifier_input.emplace_back(sp_translation_step_vk_and_incoming_message_payload_digest_bits[i]); + while (verifier_input[i].size() < padded_verifier_input_size) + { + verifier_input[i].emplace_back(zero); + } + + proof.emplace_back(r1cs_ppzksnark_proof_variable(pb, FMT("", "proof_%zu", i))); + verifiers.emplace_back(r1cs_ppzksnark_verifier_gadget(pb, + *sp_translation_step_vk, + verifier_input[i], + sp_translation_step_pcd_circuit_maker >::field_capacity(), + proof[i], + verification_result, + FMT("", "verifiers_%zu", i))); + } + + pb.set_input_sizes(input_size_in_elts()); + printf("done compliance\n"); +} + +template +void sp_compliance_step_pcd_circuit_maker::generate_r1cs_constraints() +{ + const size_t digest_size = CRH_with_bit_out_gadget::get_digest_len(); + const size_t dimension = knapsack_dimension::dimension; + print_indent(); printf("* Knapsack dimension: %zu\n", dimension); + + const size_t compliance_predicate_arity = compliance_predicate.max_arity; + print_indent(); printf("* Compliance predicate arity: %zu\n", compliance_predicate_arity); + print_indent(); printf("* Compliance predicate payload length: %zu\n", compliance_predicate.outgoing_message_payload_length); + print_indent(); printf("* Compliance predicate local data length: %zu\n", compliance_predicate.local_data_length); + print_indent(); printf("* Compliance predicate witness length: %zu\n", compliance_predicate.witness_length); + + PROFILE_CONSTRAINTS(pb, "booleanity") + { + PROFILE_CONSTRAINTS(pb, "booleanity: unpack outgoing_message") + { + unpack_outgoing_message->generate_r1cs_constraints(true); + } + + PROFILE_CONSTRAINTS(pb, "booleanity: unpack s incoming_message") + { + for (size_t i = 0; i < compliance_predicate_arity; ++i) + { + unpack_incoming_messages[i].generate_r1cs_constraints(true); + } + } + + PROFILE_CONSTRAINTS(pb, "booleanity: unpack verification key") + { + sp_translation_step_vk->generate_r1cs_constraints(true); + } + } + + PROFILE_CONSTRAINTS(pb, "(1+s) copies of hash") + { + print_indent(); printf("* Digest-size: %zu\n", digest_size); + hash_outgoing_message->generate_r1cs_constraints(); + + for (size_t i = 0; i < compliance_predicate_arity; ++i) + { + hash_incoming_messages[i].generate_r1cs_constraints(); + } + } + + PROFILE_CONSTRAINTS(pb, "s copies of repacking circuit") + { + for (size_t i = 0; i < compliance_predicate_arity; ++i) + { + unpack_sp_translation_step_vk_and_incoming_message_payload_digests[i].generate_r1cs_constraints(true); + } + } + + PROFILE_CONSTRAINTS(pb, "compliance predicate") + { + compliance_predicate_as_gadget->generate_r1cs_constraints(); + } + + PROFILE_CONSTRAINTS(pb, "s copies of verifier for translated proofs") + { + PROFILE_CONSTRAINTS(pb, "check that s proofs lie on the curve") + { + for (size_t i = 0; i < compliance_predicate_arity; ++i) + { + proof[i].generate_r1cs_constraints(); + } + } + + for (size_t i = 0; i < compliance_predicate_arity; ++i) + { + verifiers[i].generate_r1cs_constraints(); + } + } + + PROFILE_CONSTRAINTS(pb, "miscellaneous") + { + generate_r1cs_equals_const_constraint(pb, zero, FieldT::zero(), "zero"); + generate_boolean_r1cs_constraint(pb, verification_result, "verification_result"); + + /* type * (1-verification_result) = 0 */ + pb.add_r1cs_constraint(r1cs_constraint(incoming_message_types[0], 1 - verification_result, 0), "not_base_case_implies_valid_proofs"); + + /* all types equal */ + for (size_t i = 1; i < compliance_predicate.max_arity; ++i) + { + pb.add_r1cs_constraint(r1cs_constraint(1, incoming_message_types[0], incoming_message_types[i]), + FMT("", "type_%zu_equal_to_type_0", i)); + } + + pb.add_r1cs_constraint(r1cs_constraint(1, arity, compliance_predicate_arity), "full_arity"); + pb.add_r1cs_constraint(r1cs_constraint(1, outgoing_message_type, FieldT(compliance_predicate.type)), "enforce_outgoing_type"); + } + + PRINT_CONSTRAINT_PROFILING(); + print_indent(); printf("* Number of constraints in sp_compliance_step_pcd_circuit: %zu\n", pb.num_constraints()); +} + +template +r1cs_constraint_system > sp_compliance_step_pcd_circuit_maker::get_circuit() const +{ + return pb.get_constraint_system(); +} + +template +r1cs_primary_input > sp_compliance_step_pcd_circuit_maker::get_primary_input() const +{ + return pb.primary_input(); +} + +template +r1cs_auxiliary_input > sp_compliance_step_pcd_circuit_maker::get_auxiliary_input() const +{ + return pb.auxiliary_input(); +} + +template +void sp_compliance_step_pcd_circuit_maker::generate_r1cs_witness(const r1cs_ppzksnark_verification_key > &sp_translation_step_pcd_circuit_vk, + const r1cs_pcd_compliance_predicate_primary_input &compliance_predicate_primary_input, + const r1cs_pcd_compliance_predicate_auxiliary_input &compliance_predicate_auxiliary_input, + const std::vector > > &incoming_proofs) +{ + const size_t compliance_predicate_arity = compliance_predicate.max_arity; + this->pb.clear_values(); + this->pb.val(zero) = FieldT::zero(); + + compliance_predicate_as_gadget->generate_r1cs_witness(compliance_predicate_primary_input.as_r1cs_primary_input(), + compliance_predicate_auxiliary_input.as_r1cs_auxiliary_input(compliance_predicate.incoming_message_payload_lengths)); + this->pb.val(arity) = FieldT(compliance_predicate_arity); + unpack_outgoing_message->generate_r1cs_witness_from_packed(); + for (size_t i = 0; i < compliance_predicate_arity; ++i) + { + unpack_incoming_messages[i].generate_r1cs_witness_from_packed(); + } + + sp_translation_step_vk->generate_r1cs_witness(sp_translation_step_pcd_circuit_vk); + hash_outgoing_message->generate_r1cs_witness(); + for (size_t i = 0; i < compliance_predicate_arity; ++i) + { + hash_incoming_messages[i].generate_r1cs_witness(); + unpack_sp_translation_step_vk_and_incoming_message_payload_digests[i].generate_r1cs_witness_from_packed(); + } + + for (size_t i = 0; i < compliance_predicate_arity; ++i) + { + proof[i].generate_r1cs_witness(incoming_proofs[i]); + verifiers[i].generate_r1cs_witness(); + } + + if (this->pb.val(incoming_message_types[0]) != FieldT::zero()) + { + this->pb.val(verification_result) = FieldT::one(); + } + +#ifdef DEBUG + generate_r1cs_constraints(); // force generating constraints + assert(this->pb.is_satisfied()); +#endif +} + +template +size_t sp_compliance_step_pcd_circuit_maker::field_logsize() +{ + return Fr::size_in_bits(); +} + +template +size_t sp_compliance_step_pcd_circuit_maker::field_capacity() +{ + return Fr::capacity(); +} + +template +size_t sp_compliance_step_pcd_circuit_maker::input_size_in_elts() +{ + const size_t digest_size = CRH_with_field_out_gadget::get_digest_len(); + return digest_size; +} + +template +size_t sp_compliance_step_pcd_circuit_maker::input_capacity_in_bits() +{ + return input_size_in_elts() * field_capacity(); +} + +template +size_t sp_compliance_step_pcd_circuit_maker::input_size_in_bits() +{ + return input_size_in_elts() * field_logsize(); +} + +template +sp_translation_step_pcd_circuit_maker::sp_translation_step_pcd_circuit_maker(const r1cs_ppzksnark_verification_key > &sp_compliance_step_vk) +{ + /* allocate input of the translation PCD circuit */ + sp_translation_step_pcd_circuit_input.allocate(pb, input_size_in_elts(), "sp_translation_step_pcd_circuit_input"); + + /* unpack translation step PCD circuit input */ + unpacked_sp_translation_step_pcd_circuit_input.allocate(pb, sp_compliance_step_pcd_circuit_maker >::input_size_in_bits(), "unpacked_sp_translation_step_pcd_circuit_input"); + unpack_sp_translation_step_pcd_circuit_input.reset(new multipacking_gadget(pb, unpacked_sp_translation_step_pcd_circuit_input, sp_translation_step_pcd_circuit_input, field_capacity(), "unpack_sp_translation_step_pcd_circuit_input")); + + /* prepare arguments for the verifier */ + hardcoded_sp_compliance_step_vk.reset(new r1cs_ppzksnark_preprocessed_r1cs_ppzksnark_verification_key_variable(pb, sp_compliance_step_vk, "hardcoded_sp_compliance_step_vk")); + proof.reset(new r1cs_ppzksnark_proof_variable(pb, "proof")); + + /* verify previous proof */ + online_verifier.reset(new r1cs_ppzksnark_online_verifier_gadget(pb, + *hardcoded_sp_compliance_step_vk, + unpacked_sp_translation_step_pcd_circuit_input, + sp_compliance_step_pcd_circuit_maker >::field_logsize(), + *proof, + ONE, // must always accept + "verifier")); + pb.set_input_sizes(input_size_in_elts()); + + printf("done translation\n"); +} + +template +void sp_translation_step_pcd_circuit_maker::generate_r1cs_constraints() +{ + PROFILE_CONSTRAINTS(pb, "repacking: unpack circuit input") + { + unpack_sp_translation_step_pcd_circuit_input->generate_r1cs_constraints(true); + } + + PROFILE_CONSTRAINTS(pb, "verifier for compliance proofs") + { + PROFILE_CONSTRAINTS(pb, "check that proof lies on the curve") + { + proof->generate_r1cs_constraints(); + } + + online_verifier->generate_r1cs_constraints(); + } + + PRINT_CONSTRAINT_PROFILING(); + print_indent(); printf("* Number of constraints in sp_translation_step_pcd_circuit: %zu\n", pb.num_constraints()); +} + +template +r1cs_constraint_system > sp_translation_step_pcd_circuit_maker::get_circuit() const +{ + return pb.get_constraint_system(); +} + +template +void sp_translation_step_pcd_circuit_maker::generate_r1cs_witness(const r1cs_primary_input > sp_translation_step_input, + const r1cs_ppzksnark_proof > &compliance_step_proof) +{ + this->pb.clear_values(); + sp_translation_step_pcd_circuit_input.fill_with_field_elements(pb, sp_translation_step_input); + unpack_sp_translation_step_pcd_circuit_input->generate_r1cs_witness_from_packed(); + + proof->generate_r1cs_witness(compliance_step_proof); + online_verifier->generate_r1cs_witness(); + +#ifdef DEBUG + generate_r1cs_constraints(); // force generating constraints + + printf("Input to the translation circuit:\n"); + for (size_t i = 0; i < this->pb.num_inputs(); ++i) + { + this->pb.val(pb_variable(i+1)).print(); + } + + assert(this->pb.is_satisfied()); +#endif +} + +template +r1cs_primary_input > sp_translation_step_pcd_circuit_maker::get_primary_input() const +{ + return pb.primary_input(); +} + +template +r1cs_auxiliary_input > sp_translation_step_pcd_circuit_maker::get_auxiliary_input() const +{ + return pb.auxiliary_input(); +} + +template +size_t sp_translation_step_pcd_circuit_maker::field_logsize() +{ + return Fr::size_in_bits(); +} + +template +size_t sp_translation_step_pcd_circuit_maker::field_capacity() +{ + return Fr::capacity(); +} + +template +size_t sp_translation_step_pcd_circuit_maker::input_size_in_elts() +{ + return div_ceil(sp_compliance_step_pcd_circuit_maker >::input_size_in_bits(), sp_translation_step_pcd_circuit_maker::field_capacity()); +} + +template +size_t sp_translation_step_pcd_circuit_maker::input_capacity_in_bits() +{ + return input_size_in_elts() * field_capacity(); +} + +template +size_t sp_translation_step_pcd_circuit_maker::input_size_in_bits() +{ + return input_size_in_elts() * field_logsize(); +} + +template +r1cs_primary_input > get_sp_compliance_step_pcd_circuit_input(const bit_vector &sp_translation_step_vk_bits, + const r1cs_pcd_compliance_predicate_primary_input > &primary_input) +{ + enter_block("Call to get_sp_compliance_step_pcd_circuit_input"); + typedef Fr FieldT; + + const r1cs_variable_assignment outgoing_message_as_va = primary_input.outgoing_message->as_r1cs_variable_assignment(); + bit_vector msg_bits; + for (const FieldT &elt : outgoing_message_as_va) + { + const bit_vector elt_bits = convert_field_element_to_bit_vector(elt); + msg_bits.insert(msg_bits.end(), elt_bits.begin(), elt_bits.end()); + } + + bit_vector block; + block.insert(block.end(), sp_translation_step_vk_bits.begin(), sp_translation_step_vk_bits.end()); + block.insert(block.end(), msg_bits.begin(), msg_bits.end()); + + enter_block("Sample CRH randomness"); + CRH_with_field_out_gadget::sample_randomness(block.size()); + leave_block("Sample CRH randomness"); + + const std::vector digest = CRH_with_field_out_gadget::get_hash(block); + leave_block("Call to get_sp_compliance_step_pcd_circuit_input"); + + return digest; +} + +template +r1cs_primary_input > get_sp_translation_step_pcd_circuit_input(const bit_vector &sp_translation_step_vk_bits, + const r1cs_pcd_compliance_predicate_primary_input > > &primary_input) +{ + enter_block("Call to get_sp_translation_step_pcd_circuit_input"); + typedef Fr FieldT; + + const std::vector > > sp_compliance_step_pcd_circuit_input = get_sp_compliance_step_pcd_circuit_input >(sp_translation_step_vk_bits, primary_input); + bit_vector sp_compliance_step_pcd_circuit_input_bits; + for (const Fr > &elt : sp_compliance_step_pcd_circuit_input) + { + const bit_vector elt_bits = convert_field_element_to_bit_vector > >(elt); + sp_compliance_step_pcd_circuit_input_bits.insert(sp_compliance_step_pcd_circuit_input_bits.end(), elt_bits.begin(), elt_bits.end()); + } + + sp_compliance_step_pcd_circuit_input_bits.resize(sp_translation_step_pcd_circuit_maker::input_capacity_in_bits(), false); + + const r1cs_primary_input result = pack_bit_vector_into_field_element_vector(sp_compliance_step_pcd_circuit_input_bits, sp_translation_step_pcd_circuit_maker::field_capacity()); + leave_block("Call to get_sp_translation_step_pcd_circuit_input"); + + return result; +} + +} // libsnark + +#endif // SP_PCD_CIRCUITS_TCC_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/pcd/r1cs_pcd/r1cs_sp_ppzkpcd/tests/test_r1cs_sp_ppzkpcd.cpp b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/pcd/r1cs_pcd/r1cs_sp_ppzkpcd/tests/test_r1cs_sp_ppzkpcd.cpp new file mode 100644 index 0000000..1169804 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/pcd/r1cs_pcd/r1cs_sp_ppzkpcd/tests/test_r1cs_sp_ppzkpcd.cpp @@ -0,0 +1,32 @@ +/** + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ +#include "common/default_types/r1cs_ppzkpcd_pp.hpp" +#include "zk_proof_systems/pcd/r1cs_pcd/r1cs_sp_ppzkpcd/examples/run_r1cs_sp_ppzkpcd.hpp" + +using namespace libsnark; + +template +void test_tally(const size_t arity, const size_t max_layer) +{ + const size_t wordsize = 32; + const bool test_serialization = true; + const bool bit = run_r1cs_sp_ppzkpcd_tally_example(wordsize, arity, max_layer, test_serialization); + assert(bit); +} + +int main(void) +{ + typedef default_r1cs_ppzkpcd_pp PCD_pp; + + start_profiling(); + PCD_pp::init_public_params(); + + const size_t arity = 2; + const size_t max_layer = 2; + + test_tally(arity, max_layer); +} diff --git a/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzkadsnark/r1cs_ppzkadsnark/examples/demo_r1cs_ppzkadsnark.cpp b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzkadsnark/r1cs_ppzkadsnark/examples/demo_r1cs_ppzkadsnark.cpp new file mode 100644 index 0000000..717fce4 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzkadsnark/r1cs_ppzkadsnark/examples/demo_r1cs_ppzkadsnark.cpp @@ -0,0 +1,56 @@ +/** + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ +#include +#include +#include +#include +#include + +#include "common/default_types/r1cs_ppzkadsnark_pp.hpp" +#include "common/profiling.hpp" +#include "zk_proof_systems/ppzkadsnark/r1cs_ppzkadsnark/examples/run_r1cs_ppzkadsnark.hpp" + +using namespace libsnark; + +int main(int argc, const char * argv[]) +{ + default_r1cs_ppzkadsnark_pp::init_public_params(); + start_profiling(); + + if (argc == 2 && strcmp(argv[1], "-v") == 0) + { + print_compilation_info(); + return 0; + } + + if (argc != 3 && argc != 4) + { + printf("usage: %s num_constraints input_size [Fr|bytes]\n", argv[0]); + return 1; + } + const int num_constraints = atoi(argv[1]); + int input_size = atoi(argv[2]); + if (argc == 4) + { + assert(strcmp(argv[3], "Fr") == 0 || strcmp(argv[3], "bytes") == 0); + if (strcmp(argv[3], "bytes") == 0) + { + input_size = div_ceil(8 * input_size, Fr>::num_bits - 1); + } + } + + enter_block("Generate R1CS example"); + r1cs_example>> example = + generate_r1cs_example_with_field_input>> + (num_constraints, input_size); + leave_block("Generate R1CS example"); + + print_header("(enter) Profile R1CS ppzkADSNARK"); + const bool test_serialization = true; + run_r1cs_ppzkadsnark(example, test_serialization); + print_header("(leave) Profile R1CS ppzkADSNARK"); +} diff --git a/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzkadsnark/r1cs_ppzkadsnark/examples/prf/aes_ctr_prf.hpp b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzkadsnark/r1cs_ppzkadsnark/examples/prf/aes_ctr_prf.hpp new file mode 100644 index 0000000..28a655d --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzkadsnark/r1cs_ppzkadsnark/examples/prf/aes_ctr_prf.hpp @@ -0,0 +1,26 @@ +/** @file + ***************************************************************************** + + AES-Based PRF for ADSNARK. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef AESCTRPRF_HPP_ +#define AESCTRPRF_HPP_ + +#include "zk_proof_systems/ppzkadsnark/r1cs_ppzkadsnark/r1cs_ppzkadsnark_prf.hpp" + +namespace libsnark { + +class aesPrfKeyT { +public: + unsigned char key_bytes[32]; +}; + +} // libsnark + +#endif // AESCTRPRF_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzkadsnark/r1cs_ppzkadsnark/examples/prf/aes_ctr_prf.tcc b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzkadsnark/r1cs_ppzkadsnark/examples/prf/aes_ctr_prf.tcc new file mode 100644 index 0000000..c5b5d45 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzkadsnark/r1cs_ppzkadsnark/examples/prf/aes_ctr_prf.tcc @@ -0,0 +1,68 @@ +/** @file + ***************************************************************************** + + AES-Based PRF for ADSNARK. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include "common/default_types/r1cs_ppzkadsnark_pp.hpp" +#include "supercop/crypto_core_aes128encrypt.h" +#include "supercop/randombytes.h" +#include "gmp.h" + +namespace libsnark { + +template <> +aesPrfKeyT prfGen() { + aesPrfKeyT key; + randombytes(key.key_bytes,32); + return key; +} + +template<> +Fr> prfCompute( + const aesPrfKeyT &key, const labelT &label) { + unsigned char seed_bytes[16]; + mpz_t aux,Fr_mod; + unsigned char random_bytes[16*3]; + size_t exp_len; + + mpz_init (aux); + mpz_init (Fr_mod); + + // compute random seed using AES as PRF + crypto_core_aes128encrypt_openssl(seed_bytes,label.label_bytes,key.key_bytes,NULL); + + // use first 128 bits of output to seed AES-CTR + // PRG to expand to 3*128 bits + crypto_core_aes128encrypt_openssl(random_bytes,seed_bytes,key.key_bytes+16,NULL); + + mpz_import(aux, 16, 0, 1, 0, 0, seed_bytes); + mpz_add_ui(aux,aux,1); + mpz_export(seed_bytes, &exp_len, 0, 1, 0, 0, aux); + while (exp_len < 16) + seed_bytes[exp_len++] = 0; + + crypto_core_aes128encrypt_openssl(random_bytes+16,seed_bytes,key.key_bytes+16,NULL); + + mpz_add_ui(aux,aux,1); + mpz_export(seed_bytes, &exp_len, 0, 1, 0, 0, aux); + while (exp_len < 16) + seed_bytes[exp_len++] = 0; + + crypto_core_aes128encrypt_openssl(random_bytes+32,seed_bytes,key.key_bytes+16,NULL); + + // see output as integer and reduce modulo r + mpz_import(aux, 16*3, 0, 1, 0, 0, random_bytes); + Fr>::mod.to_mpz(Fr_mod); + mpz_mod(aux,aux,Fr_mod); + + return Fr>( + bigint>::num_limbs>(aux)); +} + +} // libsnark diff --git a/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzkadsnark/r1cs_ppzkadsnark/examples/run_r1cs_ppzkadsnark.hpp b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzkadsnark/r1cs_ppzkadsnark/examples/run_r1cs_ppzkadsnark.hpp new file mode 100644 index 0000000..2a919b0 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzkadsnark/r1cs_ppzkadsnark/examples/run_r1cs_ppzkadsnark.hpp @@ -0,0 +1,35 @@ +/** @file + ***************************************************************************** + + Declaration of functionality that runs the R1CS ppzkADSNARK for + a given R1CS example. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef RUN_R1CS_PPZKADSNARK_HPP_ +#define RUN_R1CS_PPZKADSNARK_HPP_ + +#include "relations/constraint_satisfaction_problems/r1cs/examples/r1cs_examples.hpp" + +namespace libsnark { + +/** + * Runs the ppzkADSNARK (generator, prover, and verifier) for a given + * R1CS example (specified by a constraint system, input, and witness). + * + * Optionally, also test the serialization routines for keys and proofs. + * (This takes additional time.) + */ +template +bool run_r1cs_ppzkadsnark(const r1cs_example> > &example, + const bool test_serialization); + +} // libsnark + +#include "zk_proof_systems/ppzkadsnark/r1cs_ppzkadsnark/examples/run_r1cs_ppzkadsnark.tcc" + +#endif // RUN_R1CS_PPZKADSNARK_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzkadsnark/r1cs_ppzkadsnark/examples/run_r1cs_ppzkadsnark.tcc b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzkadsnark/r1cs_ppzkadsnark/examples/run_r1cs_ppzkadsnark.tcc new file mode 100644 index 0000000..a69ed53 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzkadsnark/r1cs_ppzkadsnark/examples/run_r1cs_ppzkadsnark.tcc @@ -0,0 +1,123 @@ +/** @file + ***************************************************************************** + + Implementation of functionality that runs the R1CS ppzkADSNARK for + a given R1CS example. + + See run_r1cs_ppzkadsnark.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef RUN_R1CS_PPZKADSNARK_TCC_ +#define RUN_R1CS_PPZKADSNARK_TCC_ + +#include "zk_proof_systems/ppzkadsnark/r1cs_ppzkadsnark/r1cs_ppzkadsnark.hpp" +#include "zk_proof_systems/ppzkadsnark/r1cs_ppzkadsnark/examples/prf/aes_ctr_prf.tcc" +#include "zk_proof_systems/ppzkadsnark/r1cs_ppzkadsnark/examples/signature/ed25519_signature.tcc" + +#include +#include + +#include "common/profiling.hpp" + +namespace libsnark { + +/** + * The code below provides an example of all stages of running a R1CS ppzkADSNARK. + * + * Of course, in a real-life scenario, we would have three distinct entities, + * mangled into one in the demonstration below. The three entities are as follows. + * (1) The "generator", which runs the ppzkADSNARK generator on input a given + * constraint system CS to create a proving and a verification key for CS. + * (2) The "prover", which runs the ppzkADSNARK prover on input the proving key, + * a primary input for CS, and an auxiliary input for CS. + * (3) The "verifier", which runs the ppzkADSNARK verifier on input the verification key, + * a primary input for CS, and a proof. + */ +template +bool run_r1cs_ppzkadsnark(const r1cs_example> > &example, + const bool test_serialization) +{ + enter_block("Call to run_r1cs_ppzkadsnark"); + + r1cs_ppzkadsnark_auth_keys auth_keys = r1cs_ppzkadsnark_auth_generator(); + + print_header("R1CS ppzkADSNARK Generator"); + r1cs_ppzkadsnark_keypair keypair = r1cs_ppzkadsnark_generator(example.constraint_system,auth_keys.pap); + printf("\n"); print_indent(); print_mem("after generator"); + + print_header("Preprocess verification key"); + r1cs_ppzkadsnark_processed_verification_key pvk = r1cs_ppzkadsnark_verifier_process_vk(keypair.vk); + + if (test_serialization) + { + enter_block("Test serialization of keys"); + keypair.pk = reserialize >(keypair.pk); + keypair.vk = reserialize >(keypair.vk); + pvk = reserialize >(pvk); + leave_block("Test serialization of keys"); + } + + print_header("R1CS ppzkADSNARK Authenticate"); + std::vector>> data; + data.reserve(example.constraint_system.num_inputs()); + std::vector labels; + labels.reserve(example.constraint_system.num_inputs()); + for (size_t i = 0; i < example.constraint_system.num_inputs(); i++) { + labels.emplace_back(labelT()); + data.emplace_back(example.primary_input[i]); + } + std::vector> auth_data = + r1cs_ppzkadsnark_auth_sign(data,auth_keys.sak,labels); + + print_header("R1CS ppzkADSNARK Verify Symmetric"); + bool auth_res = + r1cs_ppzkadsnark_auth_verify(data,auth_data,auth_keys.sak,labels); + printf("* The verification result is: %s\n", (auth_res ? "PASS" : "FAIL")); + + print_header("R1CS ppzkADSNARK Verify Public"); + bool auth_resp = + r1cs_ppzkadsnark_auth_verify(data,auth_data,auth_keys.pak,labels); + assert (auth_res == auth_resp); + + print_header("R1CS ppzkADSNARK Prover"); + r1cs_ppzkadsnark_proof proof = r1cs_ppzkadsnark_prover(keypair.pk, example.primary_input, example.auxiliary_input,auth_data); + printf("\n"); print_indent(); print_mem("after prover"); + + if (test_serialization) + { + enter_block("Test serialization of proof"); + proof = reserialize >(proof); + leave_block("Test serialization of proof"); + } + + print_header("R1CS ppzkADSNARK Symmetric Verifier"); + bool ans = r1cs_ppzkadsnark_verifier(keypair.vk, proof,auth_keys.sak,labels); + printf("\n"); print_indent(); print_mem("after verifier"); + printf("* The verification result is: %s\n", (ans ? "PASS" : "FAIL")); + + print_header("R1CS ppzkADSNARK Symmetric Online Verifier"); + bool ans2 = r1cs_ppzkadsnark_online_verifier(pvk, proof,auth_keys.sak,labels); + assert(ans == ans2); + + print_header("R1CS ppzkADSNARK Public Verifier"); + ans = r1cs_ppzkadsnark_verifier(keypair.vk, auth_data, proof,auth_keys.pak,labels); + printf("\n"); print_indent(); print_mem("after verifier"); + printf("* The verification result is: %s\n", (ans ? "PASS" : "FAIL")); + + print_header("R1CS ppzkADSNARK Public Online Verifier"); + ans2 = r1cs_ppzkadsnark_online_verifier(pvk, auth_data, proof,auth_keys.pak,labels); + assert(ans == ans2); + + leave_block("Call to run_r1cs_ppzkadsnark"); + + return ans; +} + +} // libsnark + +#endif // RUN_R1CS_PPZKADSNARK_TCC_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzkadsnark/r1cs_ppzkadsnark/examples/signature/ed25519_signature.hpp b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzkadsnark/r1cs_ppzkadsnark/examples/signature/ed25519_signature.hpp new file mode 100644 index 0000000..560b08c --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzkadsnark/r1cs_ppzkadsnark/examples/signature/ed25519_signature.hpp @@ -0,0 +1,42 @@ +/** @file + ***************************************************************************** + + Fast batch verification signature for ADSNARK. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +/** @file + ***************************************************************************** + * @author This file was deed to libsnark by Manuel Barbosa. + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef ED25519SIG_HPP_ +#define ED25519SIG_HPP_ + +#include "zk_proof_systems/ppzkadsnark/r1cs_ppzkadsnark/r1cs_ppzkadsnark_signature.hpp" + +namespace libsnark { + +class ed25519_sigT { +public: + unsigned char sig_bytes[64]; +}; + +class ed25519_vkT { +public: + unsigned char vk_bytes[32]; +}; + +class ed25519_skT { +public: + unsigned char sk_bytes[64]; +}; + +} // libsnark + +#endif // ED25519SIG_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzkadsnark/r1cs_ppzkadsnark/examples/signature/ed25519_signature.tcc b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzkadsnark/r1cs_ppzkadsnark/examples/signature/ed25519_signature.tcc new file mode 100644 index 0000000..4183570 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzkadsnark/r1cs_ppzkadsnark/examples/signature/ed25519_signature.tcc @@ -0,0 +1,149 @@ +/** @file + ***************************************************************************** + + Fast batch verification signature for ADSNARK. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +/** @file + ***************************************************************************** + * @author This file was deed to libsnark by Manuel Barbosa. + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include "common/default_types/r1cs_ppzkadsnark_pp.hpp" +#include "supercop/crypto_sign.h" + +namespace libsnark { + +template<> +kpT sigGen(void) { + kpT keys; + crypto_sign_ed25519_amd64_51_30k_keypair(keys.vk.vk_bytes,keys.sk.sk_bytes); + return keys; +} + +template<> +ed25519_sigT sigSign(const ed25519_skT &sk, const labelT &label, + const G2> &Lambda) { + ed25519_sigT sigma; + unsigned long long sigmalen; + unsigned char signature[64+16+320]; + unsigned char message[16+320]; + + G2> Lambda_copy(Lambda); + Lambda_copy.to_affine_coordinates(); + + for(size_t i = 0; i<16;i++) + message[i] = label.label_bytes[i]; + + // More efficient way to get canonical point rep? + std::stringstream stream; + stream.rdbuf()->pubsetbuf(((char*)message)+16, 320); + stream << Lambda_copy; + size_t written = stream.tellp(); + while (written<320) + message[16+written++] = 0; + + crypto_sign_ed25519_amd64_51_30k(signature,&sigmalen,message,16+320,sk.sk_bytes); + + assert(sigmalen == 64+16+320); + + for(size_t i = 0; i<64;i++) + sigma.sig_bytes[i] = signature[i]; + + return sigma; +} + +template<> +bool sigVerif(const ed25519_vkT &vk, const labelT &label, + const G2> &Lambda, + const ed25519_sigT &sig) { + unsigned long long msglen; + unsigned char message[64+16+320]; + unsigned char signature[64+16+320]; + + G2> Lambda_copy(Lambda); + Lambda_copy.to_affine_coordinates(); + + for(size_t i = 0; i<64;i++) + signature[i] = sig.sig_bytes[i]; + + for(size_t i = 0; i<16;i++) + signature[64+i] = label.label_bytes[i]; + + // More efficient way to get canonical point rep? + std::stringstream stream; + stream.rdbuf()->pubsetbuf(((char*)signature)+64+16, 320); + stream << Lambda_copy; + size_t written = stream.tellp(); + while (written<320) + signature[64+16+written++] = 0; + + int res = crypto_sign_ed25519_amd64_51_30k_open(message,&msglen,signature,64+16+320,vk.vk_bytes); + return (res==0); +} + +template<> +bool sigBatchVerif(const ed25519_vkT &vk, const std::vector &labels, + const std::vector>> &Lambdas, + const std::vector &sigs) { + std::stringstream stream; + + assert(labels.size() == Lambdas.size()); + assert(labels.size() == sigs.size()); + + unsigned long long msglen[labels.size()]; + unsigned long long siglen[labels.size()]; + unsigned char *messages[labels.size()]; + unsigned char *signatures[labels.size()]; + unsigned char *pks[labels.size()]; + + unsigned char pk_copy[32]; + for(size_t i = 0; i < 32; i++) { + pk_copy[i] = vk.vk_bytes[i]; + } + + unsigned char *messagemem = (unsigned char*)malloc(labels.size()*(64+16+320)); + assert(messagemem != NULL); + unsigned char *signaturemem = (unsigned char*)malloc(labels.size()*(64+16+320)); + assert(signaturemem != NULL); + + for(size_t i = 0; i < labels.size(); i++) { + siglen[i] = 64+16+320; + messages[i] = messagemem+(64+16+320)*i; + signatures[i] = signaturemem+(64+16+320)*i; + pks[i] = pk_copy; + + for(size_t j = 0; j<64;j++) + signaturemem[i*(64+16+320)+j] = sigs[i].sig_bytes[j]; + + for(size_t j = 0; j<16;j++) + signaturemem[i*(64+16+320)+64+j] = labels[i].label_bytes[j]; + + // More efficient way to get canonical point rep? + G2> Lambda_copy(Lambdas[i]); + Lambda_copy.to_affine_coordinates(); + stream.clear(); + stream.rdbuf()->pubsetbuf((char*)(signaturemem+i*(64+16+320)+64+16), 320); + stream << Lambda_copy; + size_t written = stream.tellp(); + while (written<320) + signaturemem[i*(64+16+320)+64+16+written++] = 0; + + } + + int res = crypto_sign_ed25519_amd64_51_30k_open_batch( + messages,msglen, + signatures,siglen, + pks, + labels.size()); + + return (res==0); +} + +} // libsnark diff --git a/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzkadsnark/r1cs_ppzkadsnark/r1cs_ppzkadsnark.hpp b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzkadsnark/r1cs_ppzkadsnark/r1cs_ppzkadsnark.hpp new file mode 100644 index 0000000..bcf3465 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzkadsnark/r1cs_ppzkadsnark/r1cs_ppzkadsnark.hpp @@ -0,0 +1,674 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for a ppzkADSNARK for R1CS. + + This includes: + - class for authentication key (public and symmetric) + - class for authentication verification key (public and symmetric) + - class for proving key + - class for verification key + - class for processed verification key + - class for key tuple (authentication key & proving key & verification key) + - class for authenticated data + - class for proof + - generator algorithm + - authentication key generator algorithm + - prover algorithm + - verifier algorithm (public and symmetric) + - online verifier algorithm (public and symmetric) + + The implementation instantiates the construction in \[BBFR15], which in turn + is based on the r1cs_ppzkadsnark proof system. + + Acronyms: + + - R1CS = "Rank-1 Constraint Systems" + - ppzkADSNARK = "PreProcessing Zero-Knowledge Succinct Non-interactive ARgument of Knowledge Over Authenticated Data" + + References: + +\[BBFR15] +"ADSNARK: Nearly Practical and Privacy-Preserving Proofs on Authenticated Data", +Michael Backes, Manuel Barbosa, Dario Fiore, Raphael M. Reischuk, +IEEE Symposium on Security and Privacy 2015, + + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef R1CS_PPZKADSNARK_HPP_ +#define R1CS_PPZKADSNARK_HPP_ + +#include + +#include "algebra/curves/public_params.hpp" +#include "common/data_structures/accumulation_vector.hpp" +#include "algebra/knowledge_commitment/knowledge_commitment.hpp" +#include "relations/constraint_satisfaction_problems/r1cs/r1cs.hpp" +#include "zk_proof_systems/ppzkadsnark/r1cs_ppzkadsnark/r1cs_ppzkadsnark_params.hpp" +#include "zk_proof_systems/ppzkadsnark/r1cs_ppzkadsnark/r1cs_ppzkadsnark_signature.hpp" +#include "zk_proof_systems/ppzkadsnark/r1cs_ppzkadsnark/r1cs_ppzkadsnark_prf.hpp" + +namespace libsnark { + +/******************************** Public authentication parameters ********************************/ + +template +class r1cs_ppzkadsnark_pub_auth_prms; + +template +std::ostream& operator<<(std::ostream &out, const r1cs_ppzkadsnark_pub_auth_prms &pap); + +template +std::istream& operator>>(std::istream &in, r1cs_ppzkadsnark_pub_auth_prms &pap); + +/** + * Public authentication parameters for the R1CS ppzkADSNARK + */ +template +class r1cs_ppzkadsnark_pub_auth_prms { +public: + G1> I1; + + r1cs_ppzkadsnark_pub_auth_prms() {}; + r1cs_ppzkadsnark_pub_auth_prms& operator=(const r1cs_ppzkadsnark_pub_auth_prms &other) = default; + r1cs_ppzkadsnark_pub_auth_prms(const r1cs_ppzkadsnark_pub_auth_prms &other) = default; + r1cs_ppzkadsnark_pub_auth_prms(r1cs_ppzkadsnark_pub_auth_prms &&other) = default; + r1cs_ppzkadsnark_pub_auth_prms(G1> &&I1) : I1(std::move(I1)) {}; + + bool operator==(const r1cs_ppzkadsnark_pub_auth_prms &other) const; + friend std::ostream& operator<< (std::ostream &out, const r1cs_ppzkadsnark_pub_auth_prms &pap); + friend std::istream& operator>> (std::istream &in, r1cs_ppzkadsnark_pub_auth_prms &pap); +}; + +/******************************** Secret authentication key ********************************/ + +template +class r1cs_ppzkadsnark_sec_auth_key; + +template +std::ostream& operator<<(std::ostream &out, const r1cs_ppzkadsnark_sec_auth_key &key); + +template +std::istream& operator>>(std::istream &in, r1cs_ppzkadsnark_sec_auth_key &key); + +/** + * Secret authentication key for the R1CS ppzkADSNARK + */ +template +class r1cs_ppzkadsnark_sec_auth_key { +public: + Fr> i; + r1cs_ppzkadsnark_skTskp; + r1cs_ppzkadsnark_prfKeyTS; + + r1cs_ppzkadsnark_sec_auth_key() {}; + r1cs_ppzkadsnark_sec_auth_key& operator=(const r1cs_ppzkadsnark_sec_auth_key &other) = default; + r1cs_ppzkadsnark_sec_auth_key(const r1cs_ppzkadsnark_sec_auth_key &other) = default; + r1cs_ppzkadsnark_sec_auth_key(r1cs_ppzkadsnark_sec_auth_key &&other) = default; + r1cs_ppzkadsnark_sec_auth_key(Fr> &&i, + r1cs_ppzkadsnark_skT&&skp, r1cs_ppzkadsnark_prfKeyT&&S) : + i(std::move(i)), + skp(std::move(skp)), + S(std::move(S)) {}; + + bool operator==(const r1cs_ppzkadsnark_sec_auth_key &other) const; + friend std::ostream& operator<< (std::ostream &out, const r1cs_ppzkadsnark_sec_auth_key &key); + friend std::istream& operator>> (std::istream &in, r1cs_ppzkadsnark_sec_auth_key &key); +}; + +/******************************** Public authentication key ********************************/ + +template +class r1cs_ppzkadsnark_pub_auth_key; + +template +std::ostream& operator<<(std::ostream &out, const r1cs_ppzkadsnark_pub_auth_key &key); + +template +std::istream& operator>>(std::istream &in, r1cs_ppzkadsnark_pub_auth_key &key); + +/** + * Public authentication key for the R1CS ppzkADSNARK + */ +template +class r1cs_ppzkadsnark_pub_auth_key { +public: + G2> minusI2; + r1cs_ppzkadsnark_vkTvkp; + + r1cs_ppzkadsnark_pub_auth_key() {}; + r1cs_ppzkadsnark_pub_auth_key& operator=(const r1cs_ppzkadsnark_pub_auth_key &other) = default; + r1cs_ppzkadsnark_pub_auth_key(const r1cs_ppzkadsnark_pub_auth_key &other) = default; + r1cs_ppzkadsnark_pub_auth_key(r1cs_ppzkadsnark_pub_auth_key &&other) = default; + r1cs_ppzkadsnark_pub_auth_key(G2> &&minusI2, r1cs_ppzkadsnark_vkT&&vkp) : + minusI2(std::move(minusI2)), + vkp(std::move(vkp)) {}; + + bool operator==(const r1cs_ppzkadsnark_pub_auth_key &other) const; + friend std::ostream& operator<< (std::ostream &out, const r1cs_ppzkadsnark_pub_auth_key &key); + friend std::istream& operator>> (std::istream &in, r1cs_ppzkadsnark_pub_auth_key &key); +}; + +/******************************** Authentication key material ********************************/ + +template +class r1cs_ppzkadsnark_auth_keys { +public: + r1cs_ppzkadsnark_pub_auth_prms pap; + r1cs_ppzkadsnark_pub_auth_key pak; + r1cs_ppzkadsnark_sec_auth_key sak; + + r1cs_ppzkadsnark_auth_keys() {}; + r1cs_ppzkadsnark_auth_keys(r1cs_ppzkadsnark_auth_keys &&other) = default; + r1cs_ppzkadsnark_auth_keys(r1cs_ppzkadsnark_pub_auth_prms &&pap, + r1cs_ppzkadsnark_pub_auth_key &&pak, + r1cs_ppzkadsnark_sec_auth_key &&sak) : + pap(std::move(pap)), + pak(std::move(pak)), + sak(std::move(sak)) + {} +}; + +/******************************** Authenticated data ********************************/ + +template +class r1cs_ppzkadsnark_auth_data; + +template +std::ostream& operator<<(std::ostream &out, const r1cs_ppzkadsnark_auth_data &data); + +template +std::istream& operator>>(std::istream &in, r1cs_ppzkadsnark_auth_data &data); + +/** + * Authenticated data for the R1CS ppzkADSNARK + */ +template +class r1cs_ppzkadsnark_auth_data { +public: + Fr> mu; + G2> Lambda; + r1cs_ppzkadsnark_sigTsigma; + + r1cs_ppzkadsnark_auth_data() {}; + r1cs_ppzkadsnark_auth_data& operator=(const r1cs_ppzkadsnark_auth_data &other) = default; + r1cs_ppzkadsnark_auth_data(const r1cs_ppzkadsnark_auth_data &other) = default; + r1cs_ppzkadsnark_auth_data(r1cs_ppzkadsnark_auth_data &&other) = default; + r1cs_ppzkadsnark_auth_data(Fr> &&mu, + G2> &&Lambda, + r1cs_ppzkadsnark_sigT&&sigma) : + mu(std::move(mu)), + Lambda(std::move(Lambda)), + sigma(std::move(sigma)) {}; + + bool operator==(const r1cs_ppzkadsnark_auth_data &other) const; + friend std::ostream& operator<< (std::ostream &out, const r1cs_ppzkadsnark_auth_data &key); + friend std::istream& operator>> (std::istream &in, r1cs_ppzkadsnark_auth_data &key); +}; + +/******************************** Proving key ********************************/ + +template +class r1cs_ppzkadsnark_proving_key; + +template +std::ostream& operator<<(std::ostream &out, const r1cs_ppzkadsnark_proving_key &pk); + +template +std::istream& operator>>(std::istream &in, r1cs_ppzkadsnark_proving_key &pk); + +/** + * A proving key for the R1CS ppzkADSNARK. + */ +template +class r1cs_ppzkadsnark_proving_key { +public: + knowledge_commitment_vector>, G1> > A_query; + knowledge_commitment_vector>, G1> > B_query; + knowledge_commitment_vector>, G1> > C_query; + G1_vector> H_query; // t powers + G1_vector> K_query; + /* Now come the additional elements for ad */ + G1> rA_i_Z_g1; + + r1cs_ppzkadsnark_constraint_system constraint_system; + + r1cs_ppzkadsnark_proving_key() {}; + r1cs_ppzkadsnark_proving_key& operator=(const r1cs_ppzkadsnark_proving_key &other) = default; + r1cs_ppzkadsnark_proving_key(const r1cs_ppzkadsnark_proving_key &other) = default; + r1cs_ppzkadsnark_proving_key(r1cs_ppzkadsnark_proving_key &&other) = default; + r1cs_ppzkadsnark_proving_key(knowledge_commitment_vector>, + G1> > &&A_query, + knowledge_commitment_vector>, + G1> > &&B_query, + knowledge_commitment_vector>, + G1> > &&C_query, + G1_vector> &&H_query, + G1_vector> &&K_query, + G1> &&rA_i_Z_g1, + r1cs_ppzkadsnark_constraint_system &&constraint_system) : + A_query(std::move(A_query)), + B_query(std::move(B_query)), + C_query(std::move(C_query)), + H_query(std::move(H_query)), + K_query(std::move(K_query)), + rA_i_Z_g1(std::move(rA_i_Z_g1)), + constraint_system(std::move(constraint_system)) + {}; + + size_t G1_size() const + { + return 2*(A_query.domain_size() + C_query.domain_size()) + B_query.domain_size() + H_query.size() + K_query.size() + 1; + } + + size_t G2_size() const + { + return B_query.domain_size(); + } + + size_t G1_sparse_size() const + { + return 2*(A_query.size() + C_query.size()) + B_query.size() + H_query.size() + K_query.size() + 1; + } + + size_t G2_sparse_size() const + { + return B_query.size(); + } + + size_t size_in_bits() const + { + return A_query.size_in_bits() + B_query.size_in_bits() + C_query.size_in_bits() + libsnark::size_in_bits(H_query) + libsnark::size_in_bits(K_query) + G1>::size_in_bits(); + } + + void print_size() const + { + print_indent(); printf("* G1 elements in PK: %zu\n", this->G1_size()); + print_indent(); printf("* Non-zero G1 elements in PK: %zu\n", this->G1_sparse_size()); + print_indent(); printf("* G2 elements in PK: %zu\n", this->G2_size()); + print_indent(); printf("* Non-zero G2 elements in PK: %zu\n", this->G2_sparse_size()); + print_indent(); printf("* PK size in bits: %zu\n", this->size_in_bits()); + } + + bool operator==(const r1cs_ppzkadsnark_proving_key &other) const; + friend std::ostream& operator<< (std::ostream &out, const r1cs_ppzkadsnark_proving_key &pk); + friend std::istream& operator>> (std::istream &in, r1cs_ppzkadsnark_proving_key &pk); +}; + + +/******************************* Verification key ****************************/ + +template +class r1cs_ppzkadsnark_verification_key; + +template +std::ostream& operator<<(std::ostream &out, const r1cs_ppzkadsnark_verification_key &vk); + +template +std::istream& operator>>(std::istream &in, r1cs_ppzkadsnark_verification_key &vk); + +/** + * A verification key for the R1CS ppzkADSNARK. + */ +template +class r1cs_ppzkadsnark_verification_key { +public: + G2> alphaA_g2; + G1> alphaB_g1; + G2> alphaC_g2; + G2> gamma_g2; + G1> gamma_beta_g1; + G2> gamma_beta_g2; + G2> rC_Z_g2; + + G1> A0; + G1_vector> Ain; + + r1cs_ppzkadsnark_verification_key() = default; + r1cs_ppzkadsnark_verification_key(const G2> &alphaA_g2, + const G1> &alphaB_g1, + const G2> &alphaC_g2, + const G2> &gamma_g2, + const G1> &gamma_beta_g1, + const G2> &gamma_beta_g2, + const G2> &rC_Z_g2, + const G1> A0, + const G1_vector> Ain) : + alphaA_g2(alphaA_g2), + alphaB_g1(alphaB_g1), + alphaC_g2(alphaC_g2), + gamma_g2(gamma_g2), + gamma_beta_g1(gamma_beta_g1), + gamma_beta_g2(gamma_beta_g2), + rC_Z_g2(rC_Z_g2), + A0(A0), + Ain(Ain) + {}; + + size_t G1_size() const + { + return 3 + Ain.size(); + } + + size_t G2_size() const + { + return 5; + } + + size_t size_in_bits() const + { + return G1_size() * G1>::size_in_bits() + G2_size() * G2>::size_in_bits(); // possible zksnark bug + } + + void print_size() const + { + print_indent(); printf("* G1 elements in VK: %zu\n", this->G1_size()); + print_indent(); printf("* G2 elements in VK: %zu\n", this->G2_size()); + print_indent(); printf("* VK size in bits: %zu\n", this->size_in_bits()); + } + + bool operator==(const r1cs_ppzkadsnark_verification_key &other) const; + friend std::ostream& operator<< (std::ostream &out, const r1cs_ppzkadsnark_verification_key &vk); + friend std::istream& operator>> (std::istream &in, r1cs_ppzkadsnark_verification_key &vk); + + static r1cs_ppzkadsnark_verification_key dummy_verification_key(const size_t input_size); +}; + + +/************************ Processed verification key *************************/ + +template +class r1cs_ppzkadsnark_processed_verification_key; + +template +std::ostream& operator<<(std::ostream &out, const r1cs_ppzkadsnark_processed_verification_key &pvk); + +template +std::istream& operator>>(std::istream &in, r1cs_ppzkadsnark_processed_verification_key &pvk); + +/** + * A processed verification key for the R1CS ppzkADSNARK. + * + * Compared to a (non-processed) verification key, a processed verification key + * contains a small constant amount of additional pre-computed information that + * enables a faster verification time. + */ +template +class r1cs_ppzkadsnark_processed_verification_key { +public: + G2_precomp> pp_G2_one_precomp; + G2_precomp> vk_alphaA_g2_precomp; + G1_precomp> vk_alphaB_g1_precomp; + G2_precomp> vk_alphaC_g2_precomp; + G2_precomp> vk_rC_Z_g2_precomp; + G2_precomp> vk_gamma_g2_precomp; + G1_precomp> vk_gamma_beta_g1_precomp; + G2_precomp> vk_gamma_beta_g2_precomp; + G2_precomp> vk_rC_i_g2_precomp; + + G1> A0; + G1_vector> Ain; + + std::vector>> proof_g_vki_precomp; + + bool operator==(const r1cs_ppzkadsnark_processed_verification_key &other) const; + friend std::ostream& operator<< (std::ostream &out, const r1cs_ppzkadsnark_processed_verification_key &pvk); + friend std::istream& operator>> (std::istream &in, r1cs_ppzkadsnark_processed_verification_key &pvk); +}; + + +/********************************** Key pair *********************************/ + +/** + * A key pair for the R1CS ppzkADSNARK, which consists of a proving key and a verification key. + */ +template +class r1cs_ppzkadsnark_keypair { +public: + r1cs_ppzkadsnark_proving_key pk; + r1cs_ppzkadsnark_verification_key vk; + + r1cs_ppzkadsnark_keypair() = default; + r1cs_ppzkadsnark_keypair(const r1cs_ppzkadsnark_keypair &other) = default; + r1cs_ppzkadsnark_keypair(r1cs_ppzkadsnark_proving_key &&pk, + r1cs_ppzkadsnark_verification_key &&vk) : + pk(std::move(pk)), + vk(std::move(vk)) + {} + + r1cs_ppzkadsnark_keypair(r1cs_ppzkadsnark_keypair &&other) = default; +}; + + +/*********************************** Proof ***********************************/ + +template +class r1cs_ppzkadsnark_proof; + +template +std::ostream& operator<<(std::ostream &out, const r1cs_ppzkadsnark_proof &proof); + +template +std::istream& operator>>(std::istream &in, r1cs_ppzkadsnark_proof &proof); + +/** + * A proof for the R1CS ppzkADSNARK. + * + * While the proof has a structure, externally one merely opaquely produces, + * seralizes/deserializes, and verifies proofs. We only expose some information + * about the structure for statistics purposes. + */ +template +class r1cs_ppzkadsnark_proof { +public: + knowledge_commitment>, G1> > g_A; + knowledge_commitment>, G1> > g_B; + knowledge_commitment>, G1> > g_C; + G1> g_H; + G1> g_K; + knowledge_commitment>, G1> > g_Aau; + G1> muA; + + r1cs_ppzkadsnark_proof() + { + // invalid proof with valid curve points + this->g_A.g = G1> ::one(); + this->g_A.h = G1>::one(); + this->g_B.g = G2> ::one(); + this->g_B.h = G1>::one(); + this->g_C.g = G1> ::one(); + this->g_C.h = G1>::one(); + this->g_H = G1>::one(); + this->g_K = G1>::one(); + g_Aau = knowledge_commitment>, G1> > + (G1>::one(),G1>::one()); + this->muA = G1>::one(); + } + r1cs_ppzkadsnark_proof(knowledge_commitment>, + G1> > &&g_A, + knowledge_commitment>, + G1> > &&g_B, + knowledge_commitment>, + G1> > &&g_C, + G1> &&g_H, + G1> &&g_K, + knowledge_commitment>, + G1> > &&g_Aau, + G1> &&muA) : + g_A(std::move(g_A)), + g_B(std::move(g_B)), + g_C(std::move(g_C)), + g_H(std::move(g_H)), + g_K(std::move(g_K)), + g_Aau(std::move(g_Aau)), + muA(std::move(muA)) + {}; + + size_t G1_size() const + { + return 10; + } + + size_t G2_size() const + { + return 1; + } + + size_t size_in_bits() const + { + return G1_size() * G1>::size_in_bits() + G2_size() * G2>::size_in_bits(); + } + + void print_size() const + { + print_indent(); printf("* G1 elements in proof: %zu\n", this->G1_size()); + print_indent(); printf("* G2 elements in proof: %zu\n", this->G2_size()); + print_indent(); printf("* Proof size in bits: %zu\n", this->size_in_bits()); + } + + bool is_well_formed() const + { + return (g_A.g.is_well_formed() && g_A.h.is_well_formed() && + g_B.g.is_well_formed() && g_B.h.is_well_formed() && + g_C.g.is_well_formed() && g_C.h.is_well_formed() && + g_H.is_well_formed() && + g_K.is_well_formed() && + g_Aau.g.is_well_formed() && g_Aau.h.is_well_formed() && + muA.is_well_formed()); + } + + bool operator==(const r1cs_ppzkadsnark_proof &other) const; + friend std::ostream& operator<< (std::ostream &out, const r1cs_ppzkadsnark_proof &proof); + friend std::istream& operator>> (std::istream &in, r1cs_ppzkadsnark_proof &proof); +}; + + +/***************************** Main algorithms *******************************/ + +/** + * R1CS ppZKADSNARK authentication parameters generator algorithm. + */ +template +r1cs_ppzkadsnark_auth_keys r1cs_ppzkadsnark_auth_generator(void); + +/** + * R1CS ppZKADSNARK authentication algorithm. + */ +template +std::vector> r1cs_ppzkadsnark_auth_sign( + const std::vector>> &ins, + const r1cs_ppzkadsnark_sec_auth_key &sk, + const std::vector labels); + +/** + * R1CS ppZKADSNARK authentication verification algorithms. + */ +template +bool r1cs_ppzkadsnark_auth_verify(const std::vector>> &data, + const std::vector> & auth_data, + const r1cs_ppzkadsnark_sec_auth_key &sak, + const std::vector &labels); + +template +bool r1cs_ppzkadsnark_auth_verify(const std::vector>> &data, + const std::vector> & auth_data, + const r1cs_ppzkadsnark_pub_auth_key &pak, + const std::vector &labels); + +/** + * A generator algorithm for the R1CS ppzkADSNARK. + * + * Given a R1CS constraint system CS, this algorithm produces proving and verification keys for CS. + */ +template +r1cs_ppzkadsnark_keypair r1cs_ppzkadsnark_generator(const r1cs_ppzkadsnark_constraint_system &cs, + const r1cs_ppzkadsnark_pub_auth_prms &prms); + +/** + * A prover algorithm for the R1CS ppzkADSNARK. + * + * Given a R1CS primary input X and a R1CS auxiliary input Y, this algorithm + * produces a proof (of knowledge) that attests to the following statement: + * ``there exists Y such that CS(X,Y)=0''. + * Above, CS is the R1CS constraint system that was given as input to the generator algorithm. + */ +template +r1cs_ppzkadsnark_proof r1cs_ppzkadsnark_prover(const r1cs_ppzkadsnark_proving_key &pk, + const r1cs_ppzkadsnark_primary_input &primary_input, + const r1cs_ppzkadsnark_auxiliary_input &auxiliary_input, + const std::vector> &auth_data); + +/* + Below are two variants of verifier algorithm for the R1CS ppzkADSNARK. + + These are the four cases that arise from the following choices: + +1) The verifier accepts a (non-processed) verification key or, instead, a processed verification key. + In the latter case, we call the algorithm an "online verifier". + +2) The verifier uses the symmetric key or the public verification key. + In the former case we call the algorithm a "symmetric verifier". + +*/ + +/** + * Convert a (non-processed) verification key into a processed verification key. + */ +template +r1cs_ppzkadsnark_processed_verification_key r1cs_ppzkadsnark_verifier_process_vk( + const r1cs_ppzkadsnark_verification_key &vk); + +/** + * A symmetric verifier algorithm for the R1CS ppzkADSNARK that + * accepts a non-processed verification key + */ +template +bool r1cs_ppzkadsnark_verifier(const r1cs_ppzkadsnark_verification_key &vk, + const r1cs_ppzkadsnark_proof &proof, + const r1cs_ppzkadsnark_sec_auth_key & sak, + const std::vector &labels); + +/** + * A symmetric verifier algorithm for the R1CS ppzkADSNARK that + * accepts a processed verification key. + */ +template +bool r1cs_ppzkadsnark_online_verifier(const r1cs_ppzkadsnark_processed_verification_key &pvk, + const r1cs_ppzkadsnark_proof &proof, + const r1cs_ppzkadsnark_sec_auth_key & sak, + const std::vector &labels); + + +/** + * A verifier algorithm for the R1CS ppzkADSNARK that + * accepts a non-processed verification key + */ +template +bool r1cs_ppzkadsnark_verifier(const r1cs_ppzkadsnark_verification_key &vk, + const std::vector> &auth_data, + const r1cs_ppzkadsnark_proof &proof, + const r1cs_ppzkadsnark_pub_auth_key & pak, + const std::vector &labels); + +/** + * A verifier algorithm for the R1CS ppzkADSNARK that + * accepts a processed verification key. + */ +template +bool r1cs_ppzkadsnark_online_verifier(const r1cs_ppzkadsnark_processed_verification_key &pvk, + const std::vector> &auth_data, + const r1cs_ppzkadsnark_proof &proof, + const r1cs_ppzkadsnark_pub_auth_key & pak, + const std::vector &labels); + + +} // libsnark + +#include "zk_proof_systems/ppzkadsnark/r1cs_ppzkadsnark/r1cs_ppzkadsnark.tcc" + +#endif // R1CS_PPZKSNARK_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzkadsnark/r1cs_ppzkadsnark/r1cs_ppzkadsnark.tcc b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzkadsnark/r1cs_ppzkadsnark/r1cs_ppzkadsnark.tcc new file mode 100644 index 0000000..5468935 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzkadsnark/r1cs_ppzkadsnark/r1cs_ppzkadsnark.tcc @@ -0,0 +1,1207 @@ +/** @file +***************************************************************************** + +Implementation of interfaces for a ppzkADSNARK for R1CS. + +See r1cs_ppzkadsnark.hpp . + +***************************************************************************** +* @author This file is part of libsnark, developed by SCIPR Lab +* and contributors (see AUTHORS). +* @copyright MIT license (see LICENSE file) +*****************************************************************************/ + +#ifndef R1CS_PPZKADSNARK_TCC_ +#define R1CS_PPZKADSNARK_TCC_ + +#include +#include +#include +#include +#include + +#include "common/profiling.hpp" +#include "common/utils.hpp" +#include "algebra/scalar_multiplication/multiexp.hpp" +#include "algebra/scalar_multiplication/kc_multiexp.hpp" +#include "reductions/r1cs_to_qap/r1cs_to_qap.hpp" + +namespace libsnark { + + +template +bool r1cs_ppzkadsnark_pub_auth_prms::operator==(const r1cs_ppzkadsnark_pub_auth_prms &other) const +{ + return (this->I1 == other.I1); +} + +template +std::ostream& operator<<(std::ostream &out, const r1cs_ppzkadsnark_pub_auth_prms &pap) +{ + out << pap.I1; + + return out; +} + +template +std::istream& operator>>(std::istream &in, r1cs_ppzkadsnark_pub_auth_prms &pap) +{ + in >> pap.I1; + + return in; +} + +template +bool r1cs_ppzkadsnark_sec_auth_key::operator==(const r1cs_ppzkadsnark_sec_auth_key &other) const +{ + return (this->i == other.i) && + (this->skp == other.skp) && + (this->S == other.S); +} + +template +std::ostream& operator<<(std::ostream &out, const r1cs_ppzkadsnark_sec_auth_key &key) +{ + out << key.i; + out << key.skp; + out << key.S; + + return out; +} + +template +std::istream& operator>>(std::istream &in, r1cs_ppzkadsnark_sec_auth_key &key) +{ + in >> key.i; + in >> key.skp; + in >> key.S; + + return in; +} + +template +bool r1cs_ppzkadsnark_pub_auth_key::operator==(const r1cs_ppzkadsnark_pub_auth_key &other) const +{ + return (this->minusI2 == other.minusI2) && + (this->vkp == other.vkp); +} + +template +std::ostream& operator<<(std::ostream &out, const r1cs_ppzkadsnark_pub_auth_key &key) +{ + out << key.minusI2; + out << key.vkp; + + return out; +} + +template +std::istream& operator>>(std::istream &in, r1cs_ppzkadsnark_pub_auth_key &key) +{ + in >> key.minusI2; + in >> key.vkp; + + return in; +} + +template +bool r1cs_ppzkadsnark_auth_data::operator==(const r1cs_ppzkadsnark_auth_data &other) const +{ + return (this->mu == other.mu) && + (this->Lambda == other.Lambda) && + (this->sigma == other.sigma); +} + +template +std::ostream& operator<<(std::ostream &out, const r1cs_ppzkadsnark_auth_data &data) +{ + out << data.mu; + out << data.Lambda; + out << data.sigma; + + return out; +} + +template +std::istream& operator>>(std::istream &in, r1cs_ppzkadsnark_auth_data &data) +{ + in >> data.mu; + in >> data.Lambda; + data.sigma; + + return in; +} + +template +bool r1cs_ppzkadsnark_proving_key::operator==(const r1cs_ppzkadsnark_proving_key &other) const +{ + return (this->A_query == other.A_query && + this->B_query == other.B_query && + this->C_query == other.C_query && + this->H_query == other.H_query && + this->K_query == other.K_query && + this->rA_i_Z_g1 == other.rA_i_Z_g1 && + this->constraint_system == other.constraint_system); +} + +template +std::ostream& operator<<(std::ostream &out, const r1cs_ppzkadsnark_proving_key &pk) +{ + out << pk.A_query; + out << pk.B_query; + out << pk.C_query; + out << pk.H_query; + out << pk.K_query; + out << pk.rA_i_Z_g1; + out << pk.constraint_system; + + return out; +} + +template +std::istream& operator>>(std::istream &in, r1cs_ppzkadsnark_proving_key &pk) +{ + in >> pk.A_query; + in >> pk.B_query; + in >> pk.C_query; + in >> pk.H_query; + in >> pk.K_query; + in >> pk.rA_i_Z_g1; + in >> pk.constraint_system; + + return in; +} + +template +bool r1cs_ppzkadsnark_verification_key::operator==(const r1cs_ppzkadsnark_verification_key &other) const +{ + return (this->alphaA_g2 == other.alphaA_g2 && + this->alphaB_g1 == other.alphaB_g1 && + this->alphaC_g2 == other.alphaC_g2 && + this->gamma_g2 == other.gamma_g2 && + this->gamma_beta_g1 == other.gamma_beta_g1 && + this->gamma_beta_g2 == other.gamma_beta_g2 && + this->rC_Z_g2 == other.rC_Z_g2 && + this->A0 == other.A0 && + this->Ain == other.Ain); +} + +template +std::ostream& operator<<(std::ostream &out, const r1cs_ppzkadsnark_verification_key &vk) +{ + out << vk.alphaA_g2 << OUTPUT_NEWLINE; + out << vk.alphaB_g1 << OUTPUT_NEWLINE; + out << vk.alphaC_g2 << OUTPUT_NEWLINE; + out << vk.gamma_g2 << OUTPUT_NEWLINE; + out << vk.gamma_beta_g1 << OUTPUT_NEWLINE; + out << vk.gamma_beta_g2 << OUTPUT_NEWLINE; + out << vk.rC_Z_g2 << OUTPUT_NEWLINE; + out << vk.A0 << OUTPUT_NEWLINE; + out << vk.Ain << OUTPUT_NEWLINE; + + return out; +} + +template +std::istream& operator>>(std::istream &in, r1cs_ppzkadsnark_verification_key &vk) +{ + in >> vk.alphaA_g2; + consume_OUTPUT_NEWLINE(in); + in >> vk.alphaB_g1; + consume_OUTPUT_NEWLINE(in); + in >> vk.alphaC_g2; + consume_OUTPUT_NEWLINE(in); + in >> vk.gamma_g2; + consume_OUTPUT_NEWLINE(in); + in >> vk.gamma_beta_g1; + consume_OUTPUT_NEWLINE(in); + in >> vk.gamma_beta_g2; + consume_OUTPUT_NEWLINE(in); + in >> vk.rC_Z_g2; + consume_OUTPUT_NEWLINE(in); + in >> vk.A0; + consume_OUTPUT_NEWLINE(in); + in >> vk.Ain; + consume_OUTPUT_NEWLINE(in); + + return in; +} + +template +bool r1cs_ppzkadsnark_processed_verification_key::operator==( + const r1cs_ppzkadsnark_processed_verification_key &other) const +{ + bool result = (this->pp_G2_one_precomp == other.pp_G2_one_precomp && + this->vk_alphaA_g2_precomp == other.vk_alphaA_g2_precomp && + this->vk_alphaB_g1_precomp == other.vk_alphaB_g1_precomp && + this->vk_alphaC_g2_precomp == other.vk_alphaC_g2_precomp && + this->vk_rC_Z_g2_precomp == other.vk_rC_Z_g2_precomp && + this->vk_gamma_g2_precomp == other.vk_gamma_g2_precomp && + this->vk_gamma_beta_g1_precomp == other.vk_gamma_beta_g1_precomp && + this->vk_gamma_beta_g2_precomp == other.vk_gamma_beta_g2_precomp && + this->vk_rC_i_g2_precomp == other.vk_rC_i_g2_precomp && + this->A0 == other.A0 && + this->Ain == other.Ain && + this->proof_g_vki_precomp.size() == other.proof_g_vki_precomp.size()); + if (result) { + for(size_t i=0;iproof_g_vki_precomp.size();i++) + result &= this->proof_g_vki_precomp[i] == other.proof_g_vki_precomp[i]; + } + return result; +} + +template +std::ostream& operator<<(std::ostream &out, const r1cs_ppzkadsnark_processed_verification_key &pvk) +{ + out << pvk.pp_G2_one_precomp << OUTPUT_NEWLINE; + out << pvk.vk_alphaA_g2_precomp << OUTPUT_NEWLINE; + out << pvk.vk_alphaB_g1_precomp << OUTPUT_NEWLINE; + out << pvk.vk_alphaC_g2_precomp << OUTPUT_NEWLINE; + out << pvk.vk_rC_Z_g2_precomp << OUTPUT_NEWLINE; + out << pvk.vk_gamma_g2_precomp << OUTPUT_NEWLINE; + out << pvk.vk_gamma_beta_g1_precomp << OUTPUT_NEWLINE; + out << pvk.vk_gamma_beta_g2_precomp << OUTPUT_NEWLINE; + out << pvk.vk_rC_i_g2_precomp << OUTPUT_NEWLINE; + out << pvk.A0 << OUTPUT_NEWLINE; + out << pvk.Ain << OUTPUT_NEWLINE; + out << pvk.proof_g_vki_precomp << OUTPUT_NEWLINE; + + return out; +} + +template +std::istream& operator>>(std::istream &in, r1cs_ppzkadsnark_processed_verification_key &pvk) +{ + in >> pvk.pp_G2_one_precomp; + consume_OUTPUT_NEWLINE(in); + in >> pvk.vk_alphaA_g2_precomp; + consume_OUTPUT_NEWLINE(in); + in >> pvk.vk_alphaB_g1_precomp; + consume_OUTPUT_NEWLINE(in); + in >> pvk.vk_alphaC_g2_precomp; + consume_OUTPUT_NEWLINE(in); + in >> pvk.vk_rC_Z_g2_precomp; + consume_OUTPUT_NEWLINE(in); + in >> pvk.vk_gamma_g2_precomp; + consume_OUTPUT_NEWLINE(in); + in >> pvk.vk_gamma_beta_g1_precomp; + consume_OUTPUT_NEWLINE(in); + in >> pvk.vk_gamma_beta_g2_precomp; + consume_OUTPUT_NEWLINE(in); + in >> pvk.vk_rC_i_g2_precomp; + consume_OUTPUT_NEWLINE(in); + in >> pvk.A0; + consume_OUTPUT_NEWLINE(in); + in >> pvk.Ain; + consume_OUTPUT_NEWLINE(in); + in >> pvk.proof_g_vki_precomp; + consume_OUTPUT_NEWLINE(in); + + return in; +} + +template +bool r1cs_ppzkadsnark_proof::operator==(const r1cs_ppzkadsnark_proof &other) const +{ + return (this->g_A == other.g_A && + this->g_B == other.g_B && + this->g_C == other.g_C && + this->g_H == other.g_H && + this->g_K == other.g_K && + this->g_Aau == other.g_Aau && + this->muA == other.muA); +} + +template +std::ostream& operator<<(std::ostream &out, const r1cs_ppzkadsnark_proof &proof) +{ + out << proof.g_A << OUTPUT_NEWLINE; + out << proof.g_B << OUTPUT_NEWLINE; + out << proof.g_C << OUTPUT_NEWLINE; + out << proof.g_H << OUTPUT_NEWLINE; + out << proof.g_K << OUTPUT_NEWLINE; + out << proof.g_Aau << OUTPUT_NEWLINE; + out << proof.muA << OUTPUT_NEWLINE; + + return out; +} + +template +std::istream& operator>>(std::istream &in, r1cs_ppzkadsnark_proof &proof) +{ + in >> proof.g_A; + consume_OUTPUT_NEWLINE(in); + in >> proof.g_B; + consume_OUTPUT_NEWLINE(in); + in >> proof.g_C; + consume_OUTPUT_NEWLINE(in); + in >> proof.g_H; + consume_OUTPUT_NEWLINE(in); + in >> proof.g_K; + consume_OUTPUT_NEWLINE(in); + in >> proof.g_Aau; + consume_OUTPUT_NEWLINE(in); + in >> proof.muA; + consume_OUTPUT_NEWLINE(in); + + return in; +} + +template +r1cs_ppzkadsnark_verification_key r1cs_ppzkadsnark_verification_key::dummy_verification_key(const size_t input_size) +{ + r1cs_ppzkadsnark_verification_key result; + result.alphaA_g2 = Fr>::random_element() * G2>::one(); + result.alphaB_g1 = Fr>::random_element() * G1>::one(); + result.alphaC_g2 = Fr>::random_element() * G2>::one(); + result.gamma_g2 = Fr>::random_element() * G2>::one(); + result.gamma_beta_g1 = Fr>::random_element() * G1>::one(); + result.gamma_beta_g2 = Fr>::random_element() * G2>::one(); + result.rC_Z_g2 = Fr>::random_element() * G2>::one(); + + result.A0 = Fr>::random_element() * G1>::one(); + for (size_t i = 0; i < input_size; ++i) + { + result.Ain.emplace_back(Fr>::random_element() * + G1>::one()); + } + + return result; +} + +template +r1cs_ppzkadsnark_auth_keys r1cs_ppzkadsnark_auth_generator(void) { + kpT sigkp = sigGen(); + r1cs_ppzkadsnark_prfKeyTprfseed = prfGen(); + Fr> i = Fr>::random_element(); + G1> I1 = i * G1>::one(); + G2> minusI2 = G2>::zero() - + i * G2>::one(); + return r1cs_ppzkadsnark_auth_keys( + r1cs_ppzkadsnark_pub_auth_prms(std::move(I1)), + r1cs_ppzkadsnark_pub_auth_key(std::move(minusI2),std::move(sigkp.vk)), + r1cs_ppzkadsnark_sec_auth_key(std::move(i),std::move(sigkp.sk),std::move(prfseed))); +} + +template +std::vector> r1cs_ppzkadsnark_auth_sign( + const std::vector>> &ins, + const r1cs_ppzkadsnark_sec_auth_key &sk, + const std::vector labels) { + enter_block("Call to r1cs_ppzkadsnark_auth_sign"); + assert (labels.size()==ins.size()); + std::vector> res; + res.reserve(ins.size()); + for (size_t i = 0; i < ins.size();i++) { + Fr> lambda = prfCompute(sk.S,labels[i]); + G2> Lambda = lambda * G2>::one(); + r1cs_ppzkadsnark_sigTsig = sigSign(sk.skp,labels[i],Lambda); + r1cs_ppzkadsnark_auth_data val(std::move(lambda + sk.i * ins[i]), + std::move(Lambda), + std::move(sig)); + res.emplace_back(val); + } + leave_block("Call to r1cs_ppzkadsnark_auth_sign"); + return std::move(res); +} + +// symmetric +template +bool r1cs_ppzkadsnark_auth_verify(const std::vector>> &data, + const std::vector> & auth_data, + const r1cs_ppzkadsnark_sec_auth_key &sak, + const std::vector &labels) { + enter_block("Call to r1cs_ppzkadsnark_auth_verify"); + assert ((data.size()==labels.size()) && (auth_data.size()==labels.size())); + bool res = true; + for (size_t i = 0; i < data.size();i++) { + Fr> lambda = prfCompute(sak.S,labels[i]); + Fr> mup = lambda + sak.i * data[i]; + res = res && (auth_data[i].mu == mup); + } + leave_block("Call to r1cs_ppzkadsnark_auth_verify"); + return res; +} + +// public +template +bool r1cs_ppzkadsnark_auth_verify(const std::vector>> &data, + const std::vector> & auth_data, + const r1cs_ppzkadsnark_pub_auth_key &pak, + const std::vector &labels) { + enter_block("Call to r1cs_ppzkadsnark_auth_verify"); + assert ((data.size()==labels.size()) && (data.size()==auth_data.size())); + bool res = true; + for (size_t i = 0; i < auth_data.size();i++) { + G2> Mup = auth_data[i].Lambda - data[i] * pak.minusI2; + res = res && (auth_data[i].mu * G2>::one() == Mup); + res = res && sigVerif(pak.vkp,labels[i],auth_data[i].Lambda,auth_data[i].sigma); + } + leave_block("Call to r1cs_ppzkadsnark_auth_verify"); + return res; +} + +template +r1cs_ppzkadsnark_keypair r1cs_ppzkadsnark_generator(const r1cs_ppzkadsnark_constraint_system &cs, + const r1cs_ppzkadsnark_pub_auth_prms &prms) +{ + enter_block("Call to r1cs_ppzkadsnark_generator"); + + /* make the B_query "lighter" if possible */ + r1cs_ppzkadsnark_constraint_system cs_copy(cs); + cs_copy.swap_AB_if_beneficial(); + + /* draw random element at which the QAP is evaluated */ + const Fr> t = Fr>::random_element(); + + qap_instance_evaluation> > qap_inst = + r1cs_to_qap_instance_map_with_evaluation(cs_copy, t); + + print_indent(); printf("* QAP number of variables: %zu\n", qap_inst.num_variables()); + print_indent(); printf("* QAP pre degree: %zu\n", cs_copy.constraints.size()); + print_indent(); printf("* QAP degree: %zu\n", qap_inst.degree()); + print_indent(); printf("* QAP number of input variables: %zu\n", qap_inst.num_inputs()); + + enter_block("Compute query densities"); + size_t non_zero_At = 0, non_zero_Bt = 0, non_zero_Ct = 0, non_zero_Ht = 0; + for (size_t i = 0; i < qap_inst.num_variables()+1; ++i) + { + if (!qap_inst.At[i].is_zero()) + { + ++non_zero_At; + } + if (!qap_inst.Bt[i].is_zero()) + { + ++non_zero_Bt; + } + if (!qap_inst.Ct[i].is_zero()) + { + ++non_zero_Ct; + } + } + for (size_t i = 0; i < qap_inst.degree()+1; ++i) + { + if (!qap_inst.Ht[i].is_zero()) + { + ++non_zero_Ht; + } + } + leave_block("Compute query densities"); + + Fr_vector> At = std::move(qap_inst.At); // qap_inst.At is now in unspecified state, but we do not use it later + Fr_vector> Bt = std::move(qap_inst.Bt); // qap_inst.Bt is now in unspecified state, but we do not use it later + Fr_vector> Ct = std::move(qap_inst.Ct); // qap_inst.Ct is now in unspecified state, but we do not use it later + Fr_vector> Ht = std::move(qap_inst.Ht); // qap_inst.Ht is now in unspecified state, but we do not use it later + + /* append Zt to At,Bt,Ct with */ + At.emplace_back(qap_inst.Zt); + Bt.emplace_back(qap_inst.Zt); + Ct.emplace_back(qap_inst.Zt); + + const Fr> alphaA = Fr>::random_element(), + alphaB = Fr>::random_element(), + alphaC = Fr>::random_element(), + rA = Fr>::random_element(), + rB = Fr>::random_element(), + beta = Fr>::random_element(), + gamma = Fr>::random_element(); + const Fr> rC = rA * rB; + + // consrtuct the same-coefficient-check query (must happen before zeroing out the prefix of At) + Fr_vector> Kt; + Kt.reserve(qap_inst.num_variables()+4); + for (size_t i = 0; i < qap_inst.num_variables()+1; ++i) + { + Kt.emplace_back( beta * (rA * At[i] + rB * Bt[i] + rC * Ct[i] ) ); + } + Kt.emplace_back(beta * rA * qap_inst.Zt); + Kt.emplace_back(beta * rB * qap_inst.Zt); + Kt.emplace_back(beta * rC * qap_inst.Zt); + + const size_t g1_exp_count = 2*(non_zero_At - qap_inst.num_inputs() + non_zero_Ct) + non_zero_Bt + non_zero_Ht + Kt.size(); + const size_t g2_exp_count = non_zero_Bt; + + size_t g1_window = get_exp_window_size> >(g1_exp_count); + size_t g2_window = get_exp_window_size> >(g2_exp_count); + print_indent(); printf("* G1 window: %zu\n", g1_window); + print_indent(); printf("* G2 window: %zu\n", g2_window); + +#ifdef MULTICORE + const size_t chunks = omp_get_max_threads(); // to override, set OMP_NUM_THREADS env var or call omp_set_num_threads() +#else + const size_t chunks = 1; +#endif + + enter_block("Generating G1 multiexp table"); + window_table> > g1_table = + get_window_table(Fr>::size_in_bits(), g1_window, + G1>::one()); + leave_block("Generating G1 multiexp table"); + + enter_block("Generating G2 multiexp table"); + window_table> > g2_table = + get_window_table(Fr>::size_in_bits(), + g2_window, G2>::one()); + leave_block("Generating G2 multiexp table"); + + enter_block("Generate R1CS proving key"); + + enter_block("Generate knowledge commitments"); + enter_block("Compute the A-query", false); + knowledge_commitment_vector>, G1> > A_query = + kc_batch_exp(Fr>::size_in_bits(), g1_window, g1_window, g1_table, + g1_table, rA, rA*alphaA, At, chunks); + leave_block("Compute the A-query", false); + + enter_block("Compute the B-query", false); + knowledge_commitment_vector>, G1> > B_query = + kc_batch_exp(Fr>::size_in_bits(), g2_window, g1_window, g2_table, + g1_table, rB, rB*alphaB, Bt, chunks); + leave_block("Compute the B-query", false); + + enter_block("Compute the C-query", false); + knowledge_commitment_vector>, G1> > C_query = + kc_batch_exp(Fr>::size_in_bits(), g1_window, g1_window, g1_table, + g1_table, rC, rC*alphaC, Ct, chunks); + leave_block("Compute the C-query", false); + + enter_block("Compute the H-query", false); + G1_vector> H_query = batch_exp(Fr>::size_in_bits(), g1_window, g1_table, Ht); + leave_block("Compute the H-query", false); + + enter_block("Compute the K-query", false); + G1_vector> K_query = batch_exp(Fr>::size_in_bits(), g1_window, g1_table, Kt); +#ifdef USE_MIXED_ADDITION + batch_to_special> >(K_query); +#endif + leave_block("Compute the K-query", false); + + leave_block("Generate knowledge commitments"); + + leave_block("Generate R1CS proving key"); + + enter_block("Generate R1CS verification key"); + G2> alphaA_g2 = alphaA * G2>::one(); + G1> alphaB_g1 = alphaB * G1>::one(); + G2> alphaC_g2 = alphaC * G2>::one(); + G2> gamma_g2 = gamma * G2>::one(); + G1> gamma_beta_g1 = (gamma * beta) * G1>::one(); + G2> gamma_beta_g2 = (gamma * beta) * G2>::one(); + G2> rC_Z_g2 = (rC * qap_inst.Zt) * G2>::one(); + + enter_block("Generate extra authentication elements"); + G1> rA_i_Z_g1 = (rA * qap_inst.Zt) * prms.I1; + leave_block("Generate extra authentication elements"); + + enter_block("Copy encoded input coefficients for R1CS verification key"); + G1> A0 = A_query[0].g; + G1_vector> Ain; + Ain.reserve(qap_inst.num_inputs()); + for (size_t i = 0; i < qap_inst.num_inputs(); ++i) + { + Ain.emplace_back(A_query[1+i].g); + } + + leave_block("Copy encoded input coefficients for R1CS verification key"); + + leave_block("Generate R1CS verification key"); + + leave_block("Call to r1cs_ppzkadsnark_generator"); + + r1cs_ppzkadsnark_verification_key vk = r1cs_ppzkadsnark_verification_key(alphaA_g2, + alphaB_g1, + alphaC_g2, + gamma_g2, + gamma_beta_g1, + gamma_beta_g2, + rC_Z_g2, + A0, + Ain); + r1cs_ppzkadsnark_proving_key pk = r1cs_ppzkadsnark_proving_key(std::move(A_query), + std::move(B_query), + std::move(C_query), + std::move(H_query), + std::move(K_query), + std::move(rA_i_Z_g1), + std::move(cs_copy)); + + pk.print_size(); + vk.print_size(); + + return r1cs_ppzkadsnark_keypair(std::move(pk), std::move(vk)); +} + +template +r1cs_ppzkadsnark_proof r1cs_ppzkadsnark_prover(const r1cs_ppzkadsnark_proving_key &pk, + const r1cs_ppzkadsnark_primary_input &primary_input, + const r1cs_ppzkadsnark_auxiliary_input &auxiliary_input, + const std::vector> &auth_data) +{ + enter_block("Call to r1cs_ppzkadsnark_prover"); + +#ifdef DEBUG + assert(pk.constraint_system.is_satisfied(primary_input, auxiliary_input)); +#endif + + const Fr> d1 = Fr>::random_element(), + d2 = Fr>::random_element(), + d3 = Fr>::random_element(), + dauth = Fr>::random_element(); + + enter_block("Compute the polynomial H"); + const qap_witness> > qap_wit = r1cs_to_qap_witness_map(pk.constraint_system, primary_input, + auxiliary_input, d1 + dauth, d2, d3); + leave_block("Compute the polynomial H"); + +#ifdef DEBUG + const Fr> t = Fr>::random_element(); + qap_instance_evaluation> > qap_inst = r1cs_to_qap_instance_map_with_evaluation(pk.constraint_system, t); + assert(qap_inst.is_satisfied(qap_wit)); +#endif + + knowledge_commitment>, G1> > g_A = + /* pk.A_query[0] + */ d1*pk.A_query[qap_wit.num_variables()+1]; + knowledge_commitment>, G1> > g_B = + pk.B_query[0] + qap_wit.d2*pk.B_query[qap_wit.num_variables()+1]; + knowledge_commitment>, G1> > g_C = + pk.C_query[0] + qap_wit.d3*pk.C_query[qap_wit.num_variables()+1]; + + knowledge_commitment>, G1> > g_Ain = dauth*pk.A_query[qap_wit.num_variables()+1]; + + G1> g_H = G1>::zero(); + G1> g_K = (pk.K_query[0] + + qap_wit.d1*pk.K_query[qap_wit.num_variables()+1] + + qap_wit.d2*pk.K_query[qap_wit.num_variables()+2] + + qap_wit.d3*pk.K_query[qap_wit.num_variables()+3]); + +#ifdef DEBUG + for (size_t i = 0; i < qap_wit.num_inputs() + 1; ++i) + { + assert(pk.A_query[i].g == G1>::zero()); + } + assert(pk.A_query.domain_size() == qap_wit.num_variables()+2); + assert(pk.B_query.domain_size() == qap_wit.num_variables()+2); + assert(pk.C_query.domain_size() == qap_wit.num_variables()+2); + assert(pk.H_query.size() == qap_wit.degree()+1); + assert(pk.K_query.size() == qap_wit.num_variables()+4); +#endif + +#ifdef MULTICORE + const size_t chunks = omp_get_max_threads(); // to override, set OMP_NUM_THREADS env var or call omp_set_num_threads() +#else + const size_t chunks = 1; +#endif + + enter_block("Compute the proof"); + + enter_block("Compute answer to A-query", false); + g_A = g_A + kc_multi_exp_with_mixed_addition>, G1>, Fr> >(pk.A_query, + 1+qap_wit.num_inputs(), 1+qap_wit.num_variables(), + qap_wit.coefficients_for_ABCs.begin()+qap_wit.num_inputs(), + qap_wit.coefficients_for_ABCs.begin()+qap_wit.num_variables(), + chunks, true); + leave_block("Compute answer to A-query", false); + + enter_block("Compute answer to Ain-query", false); + g_Ain = g_Ain + kc_multi_exp_with_mixed_addition>, G1>, Fr> >(pk.A_query, + 1, 1+qap_wit.num_inputs(), + qap_wit.coefficients_for_ABCs.begin(), + qap_wit.coefficients_for_ABCs.begin()+qap_wit.num_inputs(), + chunks, true); + //std :: cout << "The input proof term: " << g_Ain << "\n"; + leave_block("Compute answer to Ain-query", false); + + enter_block("Compute answer to B-query", false); + g_B = g_B + kc_multi_exp_with_mixed_addition>, G1>, Fr> >(pk.B_query, + 1, 1+qap_wit.num_variables(), + qap_wit.coefficients_for_ABCs.begin(), + qap_wit.coefficients_for_ABCs.begin()+qap_wit.num_variables(), + chunks, true); + leave_block("Compute answer to B-query", false); + + enter_block("Compute answer to C-query", false); + g_C = g_C + kc_multi_exp_with_mixed_addition>, G1>, Fr> >(pk.C_query, + 1, 1+qap_wit.num_variables(), + qap_wit.coefficients_for_ABCs.begin(), + qap_wit.coefficients_for_ABCs.begin()+qap_wit.num_variables(), + chunks, true); + leave_block("Compute answer to C-query", false); + + enter_block("Compute answer to H-query", false); + g_H = g_H + multi_exp>, Fr> >(pk.H_query.begin(), + pk.H_query.begin()+qap_wit.degree()+1, + qap_wit.coefficients_for_H.begin(), + qap_wit.coefficients_for_H.begin()+qap_wit.degree()+1, + chunks, true); + leave_block("Compute answer to H-query", false); + + enter_block("Compute answer to K-query", false); + g_K = g_K + multi_exp_with_mixed_addition>, Fr> >(pk.K_query.begin()+1, + pk.K_query.begin()+1+qap_wit.num_variables(), + qap_wit.coefficients_for_ABCs.begin(), + qap_wit.coefficients_for_ABCs.begin()+qap_wit.num_variables(), + chunks, true); + leave_block("Compute answer to K-query", false); + + enter_block("Compute extra auth terms", false); + std::vector>> mus; + std::vector>> Ains; + mus.reserve(qap_wit.num_inputs()); + Ains.reserve(qap_wit.num_inputs()); + for (size_t i=0;i> muA = dauth * pk.rA_i_Z_g1; + muA = muA + multi_exp>, Fr> >(Ains.begin(), Ains.begin()+qap_wit.num_inputs(), + mus.begin(), mus.begin()+qap_wit.num_inputs(), + chunks, true); + + // To Do: Decide whether to include relevant parts of auth_data in proof + leave_block("Compute extra auth terms", false); + + leave_block("Compute the proof"); + + leave_block("Call to r1cs_ppzkadsnark_prover"); + + r1cs_ppzkadsnark_proof proof = r1cs_ppzkadsnark_proof(std::move(g_A), + std::move(g_B), + std::move(g_C), + std::move(g_H), + std::move(g_K), + std::move(g_Ain), + std::move(muA)); + proof.print_size(); + + return proof; +} + +template +r1cs_ppzkadsnark_processed_verification_key r1cs_ppzkadsnark_verifier_process_vk( + const r1cs_ppzkadsnark_verification_key &vk) +{ + enter_block("Call to r1cs_ppzkadsnark_verifier_process_vk"); + + r1cs_ppzkadsnark_processed_verification_key pvk; + pvk.pp_G2_one_precomp = snark_pp::precompute_G2(G2>::one()); + pvk.vk_alphaA_g2_precomp = snark_pp::precompute_G2(vk.alphaA_g2); + pvk.vk_alphaB_g1_precomp = snark_pp::precompute_G1(vk.alphaB_g1); + pvk.vk_alphaC_g2_precomp = snark_pp::precompute_G2(vk.alphaC_g2); + pvk.vk_rC_Z_g2_precomp = snark_pp::precompute_G2(vk.rC_Z_g2); + pvk.vk_gamma_g2_precomp = snark_pp::precompute_G2(vk.gamma_g2); + pvk.vk_gamma_beta_g1_precomp = snark_pp::precompute_G1(vk.gamma_beta_g1); + pvk.vk_gamma_beta_g2_precomp = snark_pp::precompute_G2(vk.gamma_beta_g2); + + enter_block("Pre-processing for additional auth elements"); + G2_precomp> vk_rC_z_g2_precomp = snark_pp::precompute_G2(vk.rC_Z_g2); + + pvk.A0 = G1>(vk.A0); + pvk.Ain = G1_vector>(vk.Ain); + + pvk.proof_g_vki_precomp.reserve(pvk.Ain.size()); + for(size_t i = 0; i < pvk.Ain.size();i++) { + pvk.proof_g_vki_precomp.emplace_back(snark_pp::precompute_G1(pvk.Ain[i])); + } + + leave_block("Pre-processing for additional auth elements"); + + leave_block("Call to r1cs_ppzkadsnark_verifier_process_vk"); + + return pvk; +} + +// symmetric +template +bool r1cs_ppzkadsnark_online_verifier(const r1cs_ppzkadsnark_processed_verification_key &pvk, + const r1cs_ppzkadsnark_proof &proof, + const r1cs_ppzkadsnark_sec_auth_key & sak, + const std::vector &labels) +{ + bool result = true; + enter_block("Call to r1cs_ppzkadsnark_online_verifier"); + + enter_block("Check if the proof is well-formed"); + if (!proof.is_well_formed()) + { + if (!inhibit_profiling_info) + { + print_indent(); printf("At least one of the proof elements does not lie on the curve.\n"); + } + result = false; + } + leave_block("Check if the proof is well-formed"); + + enter_block("Checking auth-specific elements"); + + enter_block("Checking A1"); + + enter_block("Compute PRFs"); + std::vector>>lambdas; + lambdas.reserve(labels.size()); + for (size_t i = 0; i < labels.size();i++) { + lambdas.emplace_back(prfCompute(sak.S,labels[i])); + } + leave_block("Compute PRFs"); + G1> prodA = sak.i * proof.g_Aau.g; + prodA = prodA + multi_exp>, Fr> >(pvk.Ain.begin(), + pvk.Ain.begin() + labels.size(), + lambdas.begin(), + lambdas.begin() + labels.size(), 1, true); + + bool result_auth = true; + + if (!(prodA == proof.muA)) { + if (!inhibit_profiling_info) + { + print_indent(); printf("Authentication check failed.\n"); + } + result_auth = false; + } + + leave_block("Checking A1"); + + enter_block("Checking A2"); + G1_precomp> proof_g_Aau_g_precomp = snark_pp::precompute_G1(proof.g_Aau.g); + G1_precomp> proof_g_Aau_h_precomp = snark_pp::precompute_G1(proof.g_Aau.h); + Fqk> kc_Aau_1 = snark_pp::miller_loop(proof_g_Aau_g_precomp, pvk.vk_alphaA_g2_precomp); + Fqk> kc_Aau_2 = snark_pp::miller_loop(proof_g_Aau_h_precomp, pvk.pp_G2_one_precomp); + GT> kc_Aau = snark_pp::final_exponentiation(kc_Aau_1 * kc_Aau_2.unitary_inverse()); + if (kc_Aau != GT>::one()) + { + if (!inhibit_profiling_info) + { + print_indent(); printf("Knowledge commitment for Aau query incorrect.\n"); + } + result_auth = false; + } + leave_block("Checking A2"); + + leave_block("Checking auth-specific elements"); + + result &= result_auth; + + enter_block("Online pairing computations"); + enter_block("Check knowledge commitment for A is valid"); + G1_precomp> proof_g_A_g_precomp = snark_pp::precompute_G1(proof.g_A.g); + G1_precomp> proof_g_A_h_precomp = snark_pp::precompute_G1(proof.g_A.h); + Fqk> kc_A_1 = snark_pp::miller_loop(proof_g_A_g_precomp, pvk.vk_alphaA_g2_precomp); + Fqk> kc_A_2 = snark_pp::miller_loop(proof_g_A_h_precomp, pvk.pp_G2_one_precomp); + GT> kc_A = snark_pp::final_exponentiation(kc_A_1 * kc_A_2.unitary_inverse()); + if (kc_A != GT>::one()) + { + if (!inhibit_profiling_info) + { + print_indent(); printf("Knowledge commitment for A query incorrect.\n"); + } + result = false; + } + leave_block("Check knowledge commitment for A is valid"); + + enter_block("Check knowledge commitment for B is valid"); + G2_precomp> proof_g_B_g_precomp = snark_pp::precompute_G2(proof.g_B.g); + G1_precomp> proof_g_B_h_precomp = snark_pp::precompute_G1(proof.g_B.h); + Fqk> kc_B_1 = snark_pp::miller_loop(pvk.vk_alphaB_g1_precomp, proof_g_B_g_precomp); + Fqk> kc_B_2 = snark_pp::miller_loop(proof_g_B_h_precomp, pvk.pp_G2_one_precomp); + GT> kc_B = snark_pp::final_exponentiation(kc_B_1 * kc_B_2.unitary_inverse()); + if (kc_B != GT>::one()) + { + if (!inhibit_profiling_info) + { + print_indent(); printf("Knowledge commitment for B query incorrect.\n"); + } + result = false; + } + leave_block("Check knowledge commitment for B is valid"); + + enter_block("Check knowledge commitment for C is valid"); + G1_precomp> proof_g_C_g_precomp = snark_pp::precompute_G1(proof.g_C.g); + G1_precomp> proof_g_C_h_precomp = snark_pp::precompute_G1(proof.g_C.h); + Fqk> kc_C_1 = snark_pp::miller_loop(proof_g_C_g_precomp, pvk.vk_alphaC_g2_precomp); + Fqk> kc_C_2 = snark_pp::miller_loop(proof_g_C_h_precomp, pvk.pp_G2_one_precomp); + GT> kc_C = snark_pp::final_exponentiation(kc_C_1 * kc_C_2.unitary_inverse()); + if (kc_C != GT>::one()) + { + if (!inhibit_profiling_info) + { + print_indent(); printf("Knowledge commitment for C query incorrect.\n"); + } + result = false; + } + leave_block("Check knowledge commitment for C is valid"); + + G1> Aacc = pvk.A0 + proof.g_Aau.g + proof.g_A.g; + + enter_block("Check QAP divisibility"); + G1_precomp> proof_g_Aacc_precomp = snark_pp::precompute_G1(Aacc); + G1_precomp> proof_g_H_precomp = snark_pp::precompute_G1(proof.g_H); + Fqk> QAP_1 = snark_pp::miller_loop(proof_g_Aacc_precomp, proof_g_B_g_precomp); + Fqk> QAP_23 = snark_pp::double_miller_loop(proof_g_H_precomp, pvk.vk_rC_Z_g2_precomp, + proof_g_C_g_precomp, pvk.pp_G2_one_precomp); + GT> QAP = snark_pp::final_exponentiation(QAP_1 * QAP_23.unitary_inverse()); + if (QAP != GT>::one()) + { + if (!inhibit_profiling_info) + { + print_indent(); printf("QAP divisibility check failed.\n"); + } + result = false; + } + leave_block("Check QAP divisibility"); + + enter_block("Check same coefficients were used"); + G1_precomp> proof_g_K_precomp = snark_pp::precompute_G1(proof.g_K); + G1_precomp> proof_g_Aacc_C_precomp = snark_pp::precompute_G1(Aacc + proof.g_C.g); + Fqk> K_1 = snark_pp::miller_loop(proof_g_K_precomp, pvk.vk_gamma_g2_precomp); + Fqk> K_23 = snark_pp::double_miller_loop(proof_g_Aacc_C_precomp, pvk.vk_gamma_beta_g2_precomp, + pvk.vk_gamma_beta_g1_precomp, proof_g_B_g_precomp); + GT> K = snark_pp::final_exponentiation(K_1 * K_23.unitary_inverse()); + if (K != GT>::one()) + { + if (!inhibit_profiling_info) + { + print_indent(); printf("Same-coefficient check failed.\n"); + } + result = false; + } + leave_block("Check same coefficients were used"); + leave_block("Online pairing computations"); + leave_block("Call to r1cs_ppzkadsnark_online_verifier"); + + return result; +} + +template +bool r1cs_ppzkadsnark_verifier(const r1cs_ppzkadsnark_verification_key &vk, + const r1cs_ppzkadsnark_proof &proof, + const r1cs_ppzkadsnark_sec_auth_key &sak, + const std::vector &labels) +{ + enter_block("Call to r1cs_ppzkadsnark_verifier"); + r1cs_ppzkadsnark_processed_verification_key pvk = r1cs_ppzkadsnark_verifier_process_vk(vk); + bool result = r1cs_ppzkadsnark_online_verifier(pvk, proof, sak, labels); + leave_block("Call to r1cs_ppzkadsnark_verifier"); + return result; +} + + +// public +template +bool r1cs_ppzkadsnark_online_verifier(const r1cs_ppzkadsnark_processed_verification_key &pvk, + const std::vector> &auth_data, + const r1cs_ppzkadsnark_proof &proof, + const r1cs_ppzkadsnark_pub_auth_key & pak, + const std::vector &labels) +{ + bool result = true; + enter_block("Call to r1cs_ppzkadsnark_online_verifier"); + + enter_block("Check if the proof is well-formed"); + if (!proof.is_well_formed()) + { + if (!inhibit_profiling_info) + { + print_indent(); printf("At least one of the proof elements does not lie on the curve.\n"); + } + result = false; + } + leave_block("Check if the proof is well-formed"); + + enter_block("Checking auth-specific elements"); + assert (labels.size()==auth_data.size()); + + enter_block("Checking A1"); + + enter_block("Checking signatures"); + std::vector>> Lambdas; + std::vector> sigs; + Lambdas.reserve(labels.size()); + sigs.reserve(labels.size()); + for (size_t i = 0; i < labels.size();i++) { + Lambdas.emplace_back(auth_data[i].Lambda); + sigs.emplace_back(auth_data[i].sigma); + } + bool result_auth = sigBatchVerif(pak.vkp,labels,Lambdas,sigs); + if (! result_auth) + { + if (!inhibit_profiling_info) + { + print_indent(); printf("Auth sig check failed.\n"); + } + } + + leave_block("Checking signatures"); + + enter_block("Checking pairings"); + // To Do: Decide whether to move pak and lambda preprocessing to offline + std::vector>> g_Lambdas_precomp; + g_Lambdas_precomp.reserve(auth_data.size()); + for(size_t i=0; i < auth_data.size(); i++) + g_Lambdas_precomp.emplace_back(snark_pp::precompute_G2(auth_data[i].Lambda)); + G2_precomp> g_minusi_precomp = snark_pp::precompute_G2(pak.minusI2); + + enter_block("Computation"); + Fqk> accum; + if(auth_data.size() % 2 == 1) { + accum = snark_pp::miller_loop(pvk.proof_g_vki_precomp[0] , g_Lambdas_precomp[0]); + } + else { + accum = Fqk>::one(); + } + for(size_t i = auth_data.size() % 2; i < labels.size();i=i+2) { + accum = accum * snark_pp::double_miller_loop(pvk.proof_g_vki_precomp[i] , g_Lambdas_precomp[i], + pvk.proof_g_vki_precomp[i+1], g_Lambdas_precomp[i+1]); + } + G1_precomp> proof_g_muA_precomp = snark_pp::precompute_G1(proof.muA); + G1_precomp> proof_g_Aau_precomp = snark_pp::precompute_G1(proof.g_Aau.g); + Fqk> accum2 = snark_pp::double_miller_loop(proof_g_muA_precomp, pvk.pp_G2_one_precomp, + proof_g_Aau_precomp, g_minusi_precomp); + GT> authPair = snark_pp::final_exponentiation(accum * accum2.unitary_inverse()); + if (authPair != GT>::one()) + { + if (!inhibit_profiling_info) + { + print_indent(); printf("Auth pairing check failed.\n"); + } + result_auth = false; + } + leave_block("Computation"); + leave_block("Checking pairings"); + + + if (!(result_auth)) { + if (!inhibit_profiling_info) + { + print_indent(); printf("Authentication check failed.\n"); + } + } + + leave_block("Checking A1"); + + enter_block("Checking A2"); + G1_precomp> proof_g_Aau_g_precomp = snark_pp::precompute_G1(proof.g_Aau.g); + G1_precomp> proof_g_Aau_h_precomp = snark_pp::precompute_G1(proof.g_Aau.h); + Fqk> kc_Aau_1 = snark_pp::miller_loop(proof_g_Aau_g_precomp, pvk.vk_alphaA_g2_precomp); + Fqk> kc_Aau_2 = snark_pp::miller_loop(proof_g_Aau_h_precomp, pvk.pp_G2_one_precomp); + GT> kc_Aau = snark_pp::final_exponentiation(kc_Aau_1 * kc_Aau_2.unitary_inverse()); + if (kc_Aau != GT>::one()) + { + if (!inhibit_profiling_info) + { + print_indent(); printf("Knowledge commitment for Aau query incorrect.\n"); + } + result_auth = false; + } + leave_block("Checking A2"); + + leave_block("Checking auth-specific elements"); + + result &= result_auth; + + enter_block("Online pairing computations"); + enter_block("Check knowledge commitment for A is valid"); + G1_precomp> proof_g_A_g_precomp = snark_pp::precompute_G1(proof.g_A.g); + G1_precomp> proof_g_A_h_precomp = snark_pp::precompute_G1(proof.g_A.h); + Fqk> kc_A_1 = snark_pp::miller_loop(proof_g_A_g_precomp, pvk.vk_alphaA_g2_precomp); + Fqk> kc_A_2 = snark_pp::miller_loop(proof_g_A_h_precomp, pvk.pp_G2_one_precomp); + GT> kc_A = snark_pp::final_exponentiation(kc_A_1 * kc_A_2.unitary_inverse()); + if (kc_A != GT>::one()) + { + if (!inhibit_profiling_info) + { + print_indent(); printf("Knowledge commitment for A query incorrect.\n"); + } + result = false; + } + leave_block("Check knowledge commitment for A is valid"); + + enter_block("Check knowledge commitment for B is valid"); + G2_precomp> proof_g_B_g_precomp = snark_pp::precompute_G2(proof.g_B.g); + G1_precomp> proof_g_B_h_precomp = snark_pp::precompute_G1(proof.g_B.h); + Fqk> kc_B_1 = snark_pp::miller_loop(pvk.vk_alphaB_g1_precomp, proof_g_B_g_precomp); + Fqk> kc_B_2 = snark_pp::miller_loop(proof_g_B_h_precomp, pvk.pp_G2_one_precomp); + GT> kc_B = snark_pp::final_exponentiation(kc_B_1 * kc_B_2.unitary_inverse()); + if (kc_B != GT>::one()) + { + if (!inhibit_profiling_info) + { + print_indent(); printf("Knowledge commitment for B query incorrect.\n"); + } + result = false; + } + leave_block("Check knowledge commitment for B is valid"); + + enter_block("Check knowledge commitment for C is valid"); + G1_precomp> proof_g_C_g_precomp = snark_pp::precompute_G1(proof.g_C.g); + G1_precomp> proof_g_C_h_precomp = snark_pp::precompute_G1(proof.g_C.h); + Fqk> kc_C_1 = snark_pp::miller_loop(proof_g_C_g_precomp, pvk.vk_alphaC_g2_precomp); + Fqk> kc_C_2 = snark_pp::miller_loop(proof_g_C_h_precomp, pvk.pp_G2_one_precomp); + GT> kc_C = snark_pp::final_exponentiation(kc_C_1 * kc_C_2.unitary_inverse()); + if (kc_C != GT>::one()) + { + if (!inhibit_profiling_info) + { + print_indent(); printf("Knowledge commitment for C query incorrect.\n"); + } + result = false; + } + leave_block("Check knowledge commitment for C is valid"); + + G1> Aacc = pvk.A0 + proof.g_Aau.g + proof.g_A.g; + + enter_block("Check QAP divisibility"); + G1_precomp> proof_g_Aacc_precomp = snark_pp::precompute_G1(Aacc); + G1_precomp> proof_g_H_precomp = snark_pp::precompute_G1(proof.g_H); + Fqk> QAP_1 = snark_pp::miller_loop(proof_g_Aacc_precomp, proof_g_B_g_precomp); + Fqk> QAP_23 = snark_pp::double_miller_loop(proof_g_H_precomp, pvk.vk_rC_Z_g2_precomp, + proof_g_C_g_precomp, pvk.pp_G2_one_precomp); + GT> QAP = snark_pp::final_exponentiation(QAP_1 * QAP_23.unitary_inverse()); + if (QAP != GT>::one()) + { + if (!inhibit_profiling_info) + { + print_indent(); printf("QAP divisibility check failed.\n"); + } + result = false; + } + leave_block("Check QAP divisibility"); + + enter_block("Check same coefficients were used"); + G1_precomp> proof_g_K_precomp = snark_pp::precompute_G1(proof.g_K); + G1_precomp> proof_g_Aacc_C_precomp = snark_pp::precompute_G1(Aacc + proof.g_C.g); + Fqk> K_1 = snark_pp::miller_loop(proof_g_K_precomp, pvk.vk_gamma_g2_precomp); + Fqk> K_23 = snark_pp::double_miller_loop(proof_g_Aacc_C_precomp, pvk.vk_gamma_beta_g2_precomp, + pvk.vk_gamma_beta_g1_precomp, proof_g_B_g_precomp); + GT> K = snark_pp::final_exponentiation(K_1 * K_23.unitary_inverse()); + if (K != GT>::one()) + { + if (!inhibit_profiling_info) + { + print_indent(); printf("Same-coefficient check failed.\n"); + } + result = false; + } + leave_block("Check same coefficients were used"); + leave_block("Online pairing computations"); + leave_block("Call to r1cs_ppzkadsnark_online_verifier"); + + return result; +} + +// public +template +bool r1cs_ppzkadsnark_verifier(const r1cs_ppzkadsnark_verification_key &vk, + const std::vector> &auth_data, + const r1cs_ppzkadsnark_proof &proof, + const r1cs_ppzkadsnark_pub_auth_key &pak, + const std::vector &labels) +{ + assert(labels.size() == auth_data.size()); + enter_block("Call to r1cs_ppzkadsnark_verifier"); + r1cs_ppzkadsnark_processed_verification_key pvk = r1cs_ppzkadsnark_verifier_process_vk(vk); + bool result = r1cs_ppzkadsnark_online_verifier(pvk, auth_data, proof, pak,labels); + leave_block("Call to r1cs_ppzkadsnark_verifier"); + return result; +} + +} // libsnark +#endif // R1CS_PPZKADSNARK_TCC_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzkadsnark/r1cs_ppzkadsnark/r1cs_ppzkadsnark_params.hpp b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzkadsnark/r1cs_ppzkadsnark/r1cs_ppzkadsnark_params.hpp new file mode 100644 index 0000000..ebfefe7 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzkadsnark/r1cs_ppzkadsnark/r1cs_ppzkadsnark_params.hpp @@ -0,0 +1,57 @@ +/** @file + ***************************************************************************** + + Declaration of public-parameter selector for the R1CS ppzkADSNARK. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef R1CS_PPZKADSNARK_PARAMS_HPP_ +#define R1CS_PPZKADSNARK_PARAMS_HPP_ + +#include "relations/constraint_satisfaction_problems/r1cs/r1cs.hpp" + +namespace libsnark { + +class labelT { +public: + unsigned char label_bytes[16]; + labelT() {}; +}; + +/** + * Below are various template aliases (used for convenience). + */ + +template +using snark_pp = typename r1cs_ppzkadsnark_ppT::snark_pp; + +template +using r1cs_ppzkadsnark_constraint_system = r1cs_constraint_system>>; + +template +using r1cs_ppzkadsnark_primary_input = r1cs_primary_input> >; + +template +using r1cs_ppzkadsnark_auxiliary_input = r1cs_auxiliary_input> >; + +template +using r1cs_ppzkadsnark_skT = typename r1cs_ppzkadsnark_ppT::skT; + +template +using r1cs_ppzkadsnark_vkT = typename r1cs_ppzkadsnark_ppT::vkT; + +template +using r1cs_ppzkadsnark_sigT = typename r1cs_ppzkadsnark_ppT::sigT; + +template +using r1cs_ppzkadsnark_prfKeyT = typename r1cs_ppzkadsnark_ppT::prfKeyT; + + +} // libsnark + +#endif // R1CS_PPZKADSNARK_PARAMS_HPP_ + diff --git a/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzkadsnark/r1cs_ppzkadsnark/r1cs_ppzkadsnark_prf.hpp b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzkadsnark/r1cs_ppzkadsnark/r1cs_ppzkadsnark_prf.hpp new file mode 100644 index 0000000..188d755 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzkadsnark/r1cs_ppzkadsnark/r1cs_ppzkadsnark_prf.hpp @@ -0,0 +1,27 @@ +/** @file + ***************************************************************************** + + Generic PRF interface for ADSNARK. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef PRF_HPP_ +#define PRF_HPP_ + +#include "zk_proof_systems/ppzkadsnark/r1cs_ppzkadsnark/r1cs_ppzkadsnark_params.hpp" + +namespace libsnark { + +template +r1cs_ppzkadsnark_prfKeyT prfGen(); + +template +Fr> prfCompute(const r1cs_ppzkadsnark_prfKeyT &key, const labelT &label); + +} // libsnark + +#endif // PRF_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzkadsnark/r1cs_ppzkadsnark/r1cs_ppzkadsnark_signature.hpp b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzkadsnark/r1cs_ppzkadsnark/r1cs_ppzkadsnark_signature.hpp new file mode 100644 index 0000000..3218a9b --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzkadsnark/r1cs_ppzkadsnark/r1cs_ppzkadsnark_signature.hpp @@ -0,0 +1,46 @@ +/** @file + ***************************************************************************** + + Generic signature interface for ADSNARK. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +/** @file + ***************************************************************************** + * @author This file was deed to libsnark by Manuel Barbosa. + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef SIGNATURE_HPP_ +#define SIGNATURE_HPP_ + +#include "zk_proof_systems/ppzkadsnark/r1cs_ppzkadsnark/r1cs_ppzkadsnark_params.hpp" + +namespace libsnark { + +template +class kpT { +public: + r1cs_ppzkadsnark_skT sk; + r1cs_ppzkadsnark_vkT vk; +}; + +template +kpT sigGen(void); + +template +r1cs_ppzkadsnark_sigT sigSign(const r1cs_ppzkadsnark_skT &sk, const labelT &label, const G2> &Lambda); + +template +bool sigVerif(const r1cs_ppzkadsnark_vkT &vk, const labelT &label, const G2> &Lambda, const r1cs_ppzkadsnark_sigT &sig); + +template +bool sigBatchVerif(const r1cs_ppzkadsnark_vkT &vk, const std::vector &labels, const std::vector>> &Lambdas, const std::vector> &sigs); + +} // libsnark + +#endif // SIGNATURE_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/bacs_ppzksnark/bacs_ppzksnark.hpp b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/bacs_ppzksnark/bacs_ppzksnark.hpp new file mode 100644 index 0000000..139c083 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/bacs_ppzksnark/bacs_ppzksnark.hpp @@ -0,0 +1,258 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for a ppzkSNARK for BACS. + + This includes: + - class for proving key + - class for verification key + - class for processed verification key + - class for key pair (proving key & verification key) + - class for proof + - generator algorithm + - prover algorithm + - verifier algorithm (with strong or weak input consistency) + - online verifier algorithm (with strong or weak input consistency) + + The implementation is a straightforward combination of: + (1) a BACS-to-R1CS reduction, and + (2) a ppzkSNARK for R1CS. + + + Acronyms: + + - BACS = "Bilinear Arithmetic Circuit Satisfiability" + - R1CS = "Rank-1 Constraint System" + - ppzkSNARK = "PreProcessing Zero-Knowledge Succinct Non-interactive ARgument of Knowledge" + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef BACS_PPZKSNARK_HPP_ +#define BACS_PPZKSNARK_HPP_ + +#include "relations/circuit_satisfaction_problems/bacs/bacs.hpp" +#include "zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.hpp" +#include "zk_proof_systems/ppzksnark/bacs_ppzksnark/bacs_ppzksnark_params.hpp" + +namespace libsnark { + +/******************************** Proving key ********************************/ + +template +class bacs_ppzksnark_proving_key; + +template +std::ostream& operator<<(std::ostream &out, const bacs_ppzksnark_proving_key &pk); + +template +std::istream& operator>>(std::istream &in, bacs_ppzksnark_proving_key &pk); + +/** + * A proving key for the BACS ppzkSNARK. + */ +template +class bacs_ppzksnark_proving_key { +public: + bacs_ppzksnark_circuit circuit; + r1cs_ppzksnark_proving_key r1cs_pk; + + bacs_ppzksnark_proving_key() {}; + bacs_ppzksnark_proving_key(const bacs_ppzksnark_proving_key &other) = default; + bacs_ppzksnark_proving_key(bacs_ppzksnark_proving_key &&other) = default; + bacs_ppzksnark_proving_key(const bacs_ppzksnark_circuit &circuit, + const r1cs_ppzksnark_proving_key &r1cs_pk) : + circuit(circuit), r1cs_pk(r1cs_pk) + {} + bacs_ppzksnark_proving_key(bacs_ppzksnark_circuit &&circuit, + r1cs_ppzksnark_proving_key &&r1cs_pk) : + circuit(std::move(circuit)), r1cs_pk(std::move(r1cs_pk)) + {} + + bacs_ppzksnark_proving_key& operator=(const bacs_ppzksnark_proving_key &other) = default; + + size_t G1_size() const + { + return r1cs_pk.G1_size(); + } + + size_t G2_size() const + { + return r1cs_pk.G2_size(); + } + + size_t G1_sparse_size() const + { + return r1cs_pk.G1_sparse_size(); + } + + size_t G2_sparse_size() const + { + return r1cs_pk.G2_sparse_size(); + } + + size_t size_in_bits() const + { + return r1cs_pk.size_in_bits(); + } + + void print_size() const + { + r1cs_pk.print_size(); + } + + bool operator==(const bacs_ppzksnark_proving_key &other) const; + friend std::ostream& operator<< (std::ostream &out, const bacs_ppzksnark_proving_key &pk); + friend std::istream& operator>> (std::istream &in, bacs_ppzksnark_proving_key &pk); +}; + + +/******************************* Verification key ****************************/ + +/** + * A verification key for the BACS ppzkSNARK. + */ +template +using bacs_ppzksnark_verification_key = r1cs_ppzksnark_verification_key; + + +/************************ Processed verification key *************************/ + +/** + * A processed verification key for the BACS ppzkSNARK. + * + * Compared to a (non-processed) verification key, a processed verification key + * contains a small constant amount of additional pre-computed information that + * enables a faster verification time. + */ +template +using bacs_ppzksnark_processed_verification_key = r1cs_ppzksnark_processed_verification_key; + + +/********************************** Key pair *********************************/ + +/** + * A key pair for the BACS ppzkSNARK, which consists of a proving key and a verification key. + */ +template +class bacs_ppzksnark_keypair { +public: + bacs_ppzksnark_proving_key pk; + bacs_ppzksnark_verification_key vk; + + bacs_ppzksnark_keypair() {}; + bacs_ppzksnark_keypair(bacs_ppzksnark_keypair &&other) = default; + bacs_ppzksnark_keypair(const bacs_ppzksnark_proving_key &pk, + const bacs_ppzksnark_verification_key &vk) : + pk(pk), + vk(vk) + {} + + bacs_ppzksnark_keypair(bacs_ppzksnark_proving_key &&pk, + bacs_ppzksnark_verification_key &&vk) : + pk(std::move(pk)), + vk(std::move(vk)) + {} +}; + + +/*********************************** Proof ***********************************/ + +/** + * A proof for the BACS ppzkSNARK. + */ +template +using bacs_ppzksnark_proof = r1cs_ppzksnark_proof; + + +/***************************** Main algorithms *******************************/ + +/** + * A generator algorithm for the BACS ppzkSNARK. + * + * Given a BACS circuit C, this algorithm produces proving and verification keys for C. + */ +template +bacs_ppzksnark_keypair bacs_ppzksnark_generator(const bacs_ppzksnark_circuit &circuit); + +/** + * A prover algorithm for the BACS ppzkSNARK. + * + * Given a BACS primary input X and a BACS auxiliary input Y, this algorithm + * produces a proof (of knowledge) that attests to the following statement: + * ``there exists Y such that C(X,Y)=0''. + * Above, C is the BACS circuit that was given as input to the generator algorithm. + */ +template +bacs_ppzksnark_proof bacs_ppzksnark_prover(const bacs_ppzksnark_proving_key &pk, + const bacs_ppzksnark_primary_input &primary_input, + const bacs_ppzksnark_auxiliary_input &auxiliary_input); + +/* + Below are four variants of verifier algorithm for the BACS ppzkSNARK. + + These are the four cases that arise from the following two choices: + + (1) The verifier accepts a (non-processed) verification key or, instead, a processed verification key. + In the latter case, we call the algorithm an "online verifier". + + (2) The verifier checks for "weak" input consistency or, instead, "strong" input consistency. + Strong input consistency requires that |primary_input| = C.num_inputs, whereas + weak input consistency requires that |primary_input| <= C.num_inputs (and + the primary input is implicitly padded with zeros up to length C.num_inputs). + */ + +/** + * A verifier algorithm for the BACS ppzkSNARK that: + * (1) accepts a non-processed verification key, and + * (2) has weak input consistency. + */ +template +bool bacs_ppzksnark_verifier_weak_IC(const bacs_ppzksnark_verification_key &vk, + const bacs_ppzksnark_primary_input &primary_input, + const bacs_ppzksnark_proof &proof); + +/** + * A verifier algorithm for the BACS ppzkSNARK that: + * (1) accepts a non-processed verification key, and + * (2) has strong input consistency. + */ +template +bool bacs_ppzksnark_verifier_strong_IC(const bacs_ppzksnark_verification_key &vk, + const bacs_ppzksnark_primary_input &primary_input, + const bacs_ppzksnark_proof &proof); + +/** + * Convert a (non-processed) verification key into a processed verification key. + */ +template +bacs_ppzksnark_processed_verification_key bacs_ppzksnark_verifier_process_vk(const bacs_ppzksnark_verification_key &vk); + +/** + * A verifier algorithm for the BACS ppzkSNARK that: + * (1) accepts a processed verification key, and + * (2) has weak input consistency. + */ +template +bool bacs_ppzksnark_online_verifier_weak_IC(const bacs_ppzksnark_processed_verification_key &pvk, + const bacs_ppzksnark_primary_input &primary_input, + const bacs_ppzksnark_proof &proof); + +/** + * A verifier algorithm for the BACS ppzkSNARK that: + * (1) accepts a processed verification key, and + * (2) has strong input consistency. + */ +template +bool bacs_ppzksnark_online_verifier_strong_IC(const bacs_ppzksnark_processed_verification_key &pvk, + const bacs_ppzksnark_primary_input &primary_input, + const bacs_ppzksnark_proof &proof); + +} // libsnark + +#include "zk_proof_systems/ppzksnark/bacs_ppzksnark/bacs_ppzksnark.tcc" + +#endif // BACS_PPZKSNARK_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/bacs_ppzksnark/bacs_ppzksnark.tcc b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/bacs_ppzksnark/bacs_ppzksnark.tcc new file mode 100644 index 0000000..b31b172 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/bacs_ppzksnark/bacs_ppzksnark.tcc @@ -0,0 +1,142 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for a ppzkSNARK for BACS. + + See bacs_ppzksnark.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef BACS_PPZKSNARK_TCC_ +#define BACS_PPZKSNARK_TCC_ + +#include "reductions/bacs_to_r1cs/bacs_to_r1cs.hpp" + +namespace libsnark { + + +template +bool bacs_ppzksnark_proving_key::operator==(const bacs_ppzksnark_proving_key &other) const +{ + return (this->circuit == other.circuit && + this->r1cs_pk == other.r1cs_pk); +} + +template +std::ostream& operator<<(std::ostream &out, const bacs_ppzksnark_proving_key &pk) +{ + out << pk.circuit << OUTPUT_NEWLINE; + out << pk.r1cs_pk << OUTPUT_NEWLINE; + + return out; +} + +template +std::istream& operator>>(std::istream &in, bacs_ppzksnark_proving_key &pk) +{ + in >> pk.circuit; + consume_OUTPUT_NEWLINE(in); + in >> pk.r1cs_pk; + consume_OUTPUT_NEWLINE(in); + + return in; +} + + +template +bacs_ppzksnark_keypair bacs_ppzksnark_generator(const bacs_ppzksnark_circuit &circuit) +{ + typedef Fr FieldT; + + enter_block("Call to bacs_ppzksnark_generator"); + const r1cs_constraint_system r1cs_cs = bacs_to_r1cs_instance_map(circuit); + const r1cs_ppzksnark_keypair r1cs_keypair = r1cs_ppzksnark_generator(r1cs_cs); + leave_block("Call to bacs_ppzksnark_generator"); + + return bacs_ppzksnark_keypair(bacs_ppzksnark_proving_key(circuit, r1cs_keypair.pk), + r1cs_keypair.vk); +} + +template +bacs_ppzksnark_proof bacs_ppzksnark_prover(const bacs_ppzksnark_proving_key &pk, + const bacs_ppzksnark_primary_input &primary_input, + const bacs_ppzksnark_auxiliary_input &auxiliary_input) +{ + typedef Fr FieldT; + + enter_block("Call to bacs_ppzksnark_prover"); + const r1cs_variable_assignment r1cs_va = bacs_to_r1cs_witness_map(pk.circuit, primary_input, auxiliary_input); + const r1cs_auxiliary_input r1cs_ai(r1cs_va.begin() + primary_input.size(), r1cs_va.end()); // TODO: faster to just change bacs_to_r1cs_witness_map into two :( + const r1cs_ppzksnark_proof r1cs_proof = r1cs_ppzksnark_prover(pk.r1cs_pk, primary_input, r1cs_ai); + leave_block("Call to bacs_ppzksnark_prover"); + + return r1cs_proof; +} + +template +bacs_ppzksnark_processed_verification_key bacs_ppzksnark_verifier_process_vk(const bacs_ppzksnark_verification_key &vk) +{ + enter_block("Call to bacs_ppzksnark_verifier_process_vk"); + const bacs_ppzksnark_processed_verification_key pvk = r1cs_ppzksnark_verifier_process_vk(vk); + leave_block("Call to bacs_ppzksnark_verifier_process_vk"); + + return pvk; +} + +template +bool bacs_ppzksnark_verifier_weak_IC(const bacs_ppzksnark_verification_key &vk, + const bacs_ppzksnark_primary_input &primary_input, + const bacs_ppzksnark_proof &proof) +{ + enter_block("Call to bacs_ppzksnark_verifier_weak_IC"); + const bacs_ppzksnark_processed_verification_key pvk = bacs_ppzksnark_verifier_process_vk(vk); + const bool bit = r1cs_ppzksnark_online_verifier_weak_IC(pvk, primary_input, proof); + leave_block("Call to bacs_ppzksnark_verifier_weak_IC"); + + return bit; +} + +template +bool bacs_ppzksnark_verifier_strong_IC(const bacs_ppzksnark_verification_key &vk, + const bacs_ppzksnark_primary_input &primary_input, + const bacs_ppzksnark_proof &proof) +{ + enter_block("Call to bacs_ppzksnark_verifier_strong_IC"); + const bacs_ppzksnark_processed_verification_key pvk = bacs_ppzksnark_verifier_process_vk(vk); + const bool bit = r1cs_ppzksnark_online_verifier_strong_IC(pvk, primary_input, proof); + leave_block("Call to bacs_ppzksnark_verifier_strong_IC"); + + return bit; +} + +template +bool bacs_ppzksnark_online_verifier_weak_IC(const bacs_ppzksnark_processed_verification_key &pvk, + const bacs_ppzksnark_primary_input &primary_input, + const bacs_ppzksnark_proof &proof) +{ + enter_block("Call to bacs_ppzksnark_online_verifier_weak_IC"); + const bool bit = r1cs_ppzksnark_online_verifier_weak_IC(pvk, primary_input, proof); + leave_block("Call to bacs_ppzksnark_online_verifier_weak_IC"); + + return bit; +} + +template +bool bacs_ppzksnark_online_verifier_strong_IC(const bacs_ppzksnark_processed_verification_key &pvk, + const bacs_ppzksnark_primary_input &primary_input, + const bacs_ppzksnark_proof &proof) +{ + enter_block("Call to bacs_ppzksnark_online_verifier_strong_IC"); + const bool bit = r1cs_ppzksnark_online_verifier_strong_IC(pvk, primary_input, proof); + leave_block("Call to bacs_ppzksnark_online_verifier_strong_IC"); + + return bit; +} + +} // libsnark + +#endif // BACS_PPZKSNARK_TCC_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/bacs_ppzksnark/bacs_ppzksnark_params.hpp b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/bacs_ppzksnark/bacs_ppzksnark_params.hpp new file mode 100644 index 0000000..ca3538a --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/bacs_ppzksnark/bacs_ppzksnark_params.hpp @@ -0,0 +1,34 @@ +/** @file + ***************************************************************************** + + Declaration of public-parameter selector for the BACS ppzkSNARK. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef BACS_PPZKSNARK_PARAMS_HPP_ +#define BACS_PPZKSNARK_PARAMS_HPP_ + +#include "relations/circuit_satisfaction_problems/bacs/bacs.hpp" + +namespace libsnark { + +/** + * Below are various template aliases (used for convenience). + */ + +template +using bacs_ppzksnark_circuit = bacs_circuit >; + +template +using bacs_ppzksnark_primary_input = bacs_primary_input >; + +template +using bacs_ppzksnark_auxiliary_input = bacs_auxiliary_input >; + +} // libsnark + +#endif // BACS_PPZKSNARK_PARAMS_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/bacs_ppzksnark/examples/run_bacs_ppzksnark.hpp b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/bacs_ppzksnark/examples/run_bacs_ppzksnark.hpp new file mode 100644 index 0000000..1798493 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/bacs_ppzksnark/examples/run_bacs_ppzksnark.hpp @@ -0,0 +1,35 @@ +/** @file + ***************************************************************************** + + Declaration of functionality that runs the BACS ppzkSNARK for + a given BACS example. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef RUN_BACS_PPZKSNARK_HPP_ +#define RUN_BACS_PPZKSNARK_HPP_ + +#include "relations/circuit_satisfaction_problems/bacs/examples/bacs_examples.hpp" + +namespace libsnark { + +/** + * Runs the ppzkSNARK (generator, prover, and verifier) for a given + * BACS example (specified by a circuit, primary input, and auxiliary input). + * + * Optionally, also test the serialization routines for keys and proofs. + * (This takes additional time.) + */ +template +bool run_bacs_ppzksnark(const bacs_example > &example, + const bool test_serialization); + +} // libsnark + +#include "zk_proof_systems/ppzksnark/bacs_ppzksnark/examples/run_bacs_ppzksnark.tcc" + +#endif // RUN_BACS_PPZKSNARK_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/bacs_ppzksnark/examples/run_bacs_ppzksnark.tcc b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/bacs_ppzksnark/examples/run_bacs_ppzksnark.tcc new file mode 100644 index 0000000..ecb1a24 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/bacs_ppzksnark/examples/run_bacs_ppzksnark.tcc @@ -0,0 +1,87 @@ +/** @file + ***************************************************************************** + + Implementation of functionality that runs the BACS ppzkSNARK for + a given BACS example. + + See run_bacs_ppzksnark.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef RUN_BACS_PPZKSNARK_TCC_ +#define RUN_BACS_PPZKSNARK_TCC_ + +#include "zk_proof_systems/ppzksnark/bacs_ppzksnark/bacs_ppzksnark.hpp" + +#include + +#include "common/profiling.hpp" + +namespace libsnark { + +/** + * The code below provides an example of all stages of running a BACS ppzkSNARK. + * + * Of course, in a real-life scenario, we would have three distinct entities, + * mangled into one in the demonstration below. The three entities are as follows. + * (1) The "generator", which runs the ppzkSNARK generator on input a given + * circuit C to create a proving and a verification key for C. + * (2) The "prover", which runs the ppzkSNARK prover on input the proving key, + * a primary input for C, and an auxiliary input for C. + * (3) The "verifier", which runs the ppzkSNARK verifier on input the verification key, + * a primary input for C, and a proof. + */ +template +bool run_bacs_ppzksnark(const bacs_example > &example, + const bool test_serialization) +{ + enter_block("Call to run_bacs_ppzksnark"); + + print_header("BACS ppzkSNARK Generator"); + bacs_ppzksnark_keypair keypair = bacs_ppzksnark_generator(example.circuit); + printf("\n"); print_indent(); print_mem("after generator"); + + print_header("Preprocess verification key"); + bacs_ppzksnark_processed_verification_key pvk = bacs_ppzksnark_verifier_process_vk(keypair.vk); + + if (test_serialization) + { + enter_block("Test serialization of keys"); + keypair.pk = reserialize >(keypair.pk); + keypair.vk = reserialize >(keypair.vk); + pvk = reserialize >(pvk); + leave_block("Test serialization of keys"); + } + + print_header("BACS ppzkSNARK Prover"); + bacs_ppzksnark_proof proof = bacs_ppzksnark_prover(keypair.pk, example.primary_input, example.auxiliary_input); + printf("\n"); print_indent(); print_mem("after prover"); + + if (test_serialization) + { + enter_block("Test serialization of proof"); + proof = reserialize >(proof); + leave_block("Test serialization of proof"); + } + + print_header("BACS ppzkSNARK Verifier"); + bool ans = bacs_ppzksnark_verifier_strong_IC(keypair.vk, example.primary_input, proof); + printf("\n"); print_indent(); print_mem("after verifier"); + printf("* The verification result is: %s\n", (ans ? "PASS" : "FAIL")); + + print_header("BACS ppzkSNARK Online Verifier"); + bool ans2 = bacs_ppzksnark_online_verifier_strong_IC(pvk, example.primary_input, proof); + assert(ans == ans2); + + leave_block("Call to run_bacs_ppzksnark"); + + return ans; +} + +} // libsnark + +#endif // RUN_BACS_PPZKSNARK_TCC_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/bacs_ppzksnark/profiling/profile_bacs_ppzksnark.cpp b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/bacs_ppzksnark/profiling/profile_bacs_ppzksnark.cpp new file mode 100644 index 0000000..585f759 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/bacs_ppzksnark/profiling/profile_bacs_ppzksnark.cpp @@ -0,0 +1,59 @@ +/** @file + ***************************************************************************** + Profiling program that exercises the ppzkSNARK (first generator, then prover, + then verifier) on a synthetic BACS instance. + + The command + + $ src/zk_proof_systems/bacs_ppzksnark/profiling/profile_bacs_ppzksnark 1000 10 + + exercises the ppzkSNARK (first generator, then prover, then verifier) on an BACS instance with 1000 gates and an input consisting of 10 Field elements + + (If you get the error `zmInit ERR:can't protect`, see the discussion [above](#elliptic-curve-choices).) + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include + +#include "common/default_types/bacs_ppzksnark_pp.hpp" +#include "common/profiling.hpp" +#include "relations/circuit_satisfaction_problems/bacs/examples/bacs_examples.hpp" +#include "zk_proof_systems/ppzksnark/bacs_ppzksnark/examples/run_bacs_ppzksnark.hpp" + +using namespace libsnark; + +int main(int argc, const char * argv[]) +{ + default_bacs_ppzksnark_pp::init_public_params(); + start_profiling(); + + if (argc == 2 && strcmp(argv[1], "-v") == 0) + { + print_compilation_info(); + return 0; + } + + if (argc != 3) + { + printf("usage: %s num_gates primary_input_size\n", argv[0]); + return 1; + } + const int num_gates = atoi(argv[1]); + int primary_input_size = atoi(argv[2]); + + const size_t auxiliary_input_size = 0; + const size_t num_outputs = num_gates / 2; + + enter_block("Generate BACS example"); + bacs_example > example = generate_bacs_example >(primary_input_size, auxiliary_input_size, num_gates, num_outputs); + leave_block("Generate BACS example"); + + print_header("(enter) Profile BACS ppzkSNARK"); + const bool test_serialization = true; + run_bacs_ppzksnark(example, test_serialization); + print_header("(leave) Profile BACS ppzkSNARK"); +} diff --git a/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/bacs_ppzksnark/tests/test_bacs_ppzksnark.cpp b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/bacs_ppzksnark/tests/test_bacs_ppzksnark.cpp new file mode 100644 index 0000000..6dede05 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/bacs_ppzksnark/tests/test_bacs_ppzksnark.cpp @@ -0,0 +1,46 @@ +/** @file + ***************************************************************************** + Test program that exercises the ppzkSNARK (first generator, then + prover, then verifier) on a synthetic BACS instance. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ +#include +#include + +#include "common/default_types/bacs_ppzksnark_pp.hpp" +#include "common/profiling.hpp" +#include "relations/circuit_satisfaction_problems/bacs/examples/bacs_examples.hpp" +#include "zk_proof_systems/ppzksnark/bacs_ppzksnark/examples/run_bacs_ppzksnark.hpp" + +using namespace libsnark; + +template +void test_bacs_ppzksnark(const size_t primary_input_size, + const size_t auxiliary_input_size, + const size_t num_gates, + const size_t num_outputs) +{ + print_header("(enter) Test BACS ppzkSNARK"); + + const bool test_serialization = true; + const bacs_example > example = generate_bacs_example >(primary_input_size, auxiliary_input_size, num_gates, num_outputs); +#ifdef DEBUG + example.circuit.print(); +#endif + const bool bit = run_bacs_ppzksnark(example, test_serialization); + assert(bit); + + print_header("(leave) Test BACS ppzkSNARK"); +} + +int main() +{ + default_bacs_ppzksnark_pp::init_public_params(); + start_profiling(); + + test_bacs_ppzksnark(10, 10, 20, 5); +} diff --git a/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/r1cs_gg_ppzksnark/examples/run_r1cs_gg_ppzksnark.hpp b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/r1cs_gg_ppzksnark/examples/run_r1cs_gg_ppzksnark.hpp new file mode 100644 index 0000000..1eef742 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/r1cs_gg_ppzksnark/examples/run_r1cs_gg_ppzksnark.hpp @@ -0,0 +1,35 @@ +/** @file + ***************************************************************************** + + Declaration of functionality that runs the R1CS GG-ppzkSNARK for + a given R1CS example. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef RUN_R1CS_GG_PPZKSNARK_HPP_ +#define RUN_R1CS_GG_PPZKSNARK_HPP_ + +#include "relations/constraint_satisfaction_problems/r1cs/examples/r1cs_examples.hpp" + +namespace libsnark { + +/** + * Runs the ppzkSNARK (generator, prover, and verifier) for a given + * R1CS example (specified by a constraint system, input, and witness). + * + * Optionally, also test the serialization routines for keys and proofs. + * (This takes additional time.) + */ +template +bool run_r1cs_gg_ppzksnark(const r1cs_example > &example, + const bool test_serialization); + +} // libsnark + +#include "zk_proof_systems/ppzksnark/r1cs_gg_ppzksnark/examples/run_r1cs_gg_ppzksnark.tcc" + +#endif // RUN_R1CS_GG_PPZKSNARK_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/r1cs_gg_ppzksnark/examples/run_r1cs_gg_ppzksnark.tcc b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/r1cs_gg_ppzksnark/examples/run_r1cs_gg_ppzksnark.tcc new file mode 100644 index 0000000..032617e --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/r1cs_gg_ppzksnark/examples/run_r1cs_gg_ppzksnark.tcc @@ -0,0 +1,114 @@ +/** @file + ***************************************************************************** + + Implementation of functionality that runs the R1CS GG-ppzkSNARK for + a given R1CS example. + + See run_r1cs_gg_ppzksnark.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef RUN_R1CS_GG_PPZKSNARK_TCC_ +#define RUN_R1CS_GG_PPZKSNARK_TCC_ + +#include "zk_proof_systems/ppzksnark/r1cs_gg_ppzksnark/r1cs_gg_ppzksnark.hpp" + +#include +#include + +#include "common/profiling.hpp" + +namespace libsnark { + +template +typename std::enable_if::type +test_affine_verifier(const r1cs_gg_ppzksnark_verification_key &vk, + const r1cs_gg_ppzksnark_primary_input &primary_input, + const r1cs_gg_ppzksnark_proof &proof, + const bool expected_answer) +{ + print_header("R1CS GG-ppzkSNARK Affine Verifier"); + const bool answer = r1cs_gg_ppzksnark_affine_verifier_weak_IC(vk, primary_input, proof); + assert(answer == expected_answer); +} + +template +typename std::enable_if::type +test_affine_verifier(const r1cs_gg_ppzksnark_verification_key &vk, + const r1cs_gg_ppzksnark_primary_input &primary_input, + const r1cs_gg_ppzksnark_proof &proof, + const bool expected_answer) +{ + print_header("R1CS GG-ppzkSNARK Affine Verifier"); + UNUSED(vk, primary_input, proof, expected_answer); + printf("Affine verifier is not supported; not testing anything.\n"); +} + +/** + * The code below provides an example of all stages of running a R1CS GG-ppzkSNARK. + * + * Of course, in a real-life scenario, we would have three distinct entities, + * mangled into one in the demonstration below. The three entities are as follows. + * (1) The "generator", which runs the ppzkSNARK generator on input a given + * constraint system CS to create a proving and a verification key for CS. + * (2) The "prover", which runs the ppzkSNARK prover on input the proving key, + * a primary input for CS, and an auxiliary input for CS. + * (3) The "verifier", which runs the ppzkSNARK verifier on input the verification key, + * a primary input for CS, and a proof. + */ +template +bool run_r1cs_gg_ppzksnark(const r1cs_example > &example, + const bool test_serialization) +{ + enter_block("Call to run_r1cs_gg_ppzksnark"); + + print_header("R1CS GG-ppzkSNARK Generator"); + r1cs_gg_ppzksnark_keypair keypair = r1cs_gg_ppzksnark_generator(example.constraint_system); + printf("\n"); print_indent(); print_mem("after generator"); + + print_header("Preprocess verification key"); + r1cs_gg_ppzksnark_processed_verification_key pvk = r1cs_gg_ppzksnark_verifier_process_vk(keypair.vk); + + if (test_serialization) + { + enter_block("Test serialization of keys"); + keypair.pk = reserialize >(keypair.pk); + keypair.vk = reserialize >(keypair.vk); + pvk = reserialize >(pvk); + leave_block("Test serialization of keys"); + } + + print_header("R1CS GG-ppzkSNARK Prover"); + r1cs_gg_ppzksnark_proof proof = r1cs_gg_ppzksnark_prover(keypair.pk, example.primary_input, example.auxiliary_input); + printf("\n"); print_indent(); print_mem("after prover"); + + if (test_serialization) + { + enter_block("Test serialization of proof"); + proof = reserialize >(proof); + leave_block("Test serialization of proof"); + } + + print_header("R1CS GG-ppzkSNARK Verifier"); + const bool ans = r1cs_gg_ppzksnark_verifier_strong_IC(keypair.vk, example.primary_input, proof); + printf("\n"); print_indent(); print_mem("after verifier"); + printf("* The verification result is: %s\n", (ans ? "PASS" : "FAIL")); + + print_header("R1CS GG-ppzkSNARK Online Verifier"); + const bool ans2 = r1cs_gg_ppzksnark_online_verifier_strong_IC(pvk, example.primary_input, proof); + assert(ans == ans2); + + test_affine_verifier(keypair.vk, example.primary_input, proof, ans); + + leave_block("Call to run_r1cs_gg_ppzksnark"); + + return ans; +} + +} // libsnark + +#endif // RUN_R1CS_GG_PPZKSNARK_TCC_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/r1cs_gg_ppzksnark/profiling/profile_r1cs_gg_ppzksnark.cpp b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/r1cs_gg_ppzksnark/profiling/profile_r1cs_gg_ppzksnark.cpp new file mode 100644 index 0000000..4d1dc6c --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/r1cs_gg_ppzksnark/profiling/profile_r1cs_gg_ppzksnark.cpp @@ -0,0 +1,71 @@ +/** @file + ***************************************************************************** + Profiling program that exercises the ppzkSNARK (first generator, then prover, + then verifier) on a synthetic R1CS instance. + + The command + + $ src/zk_proof_systems/ppzksnark/r1cs_gg_ppzksnark/profiling/profile_r1cs_gg_ppzksnark 1000 10 Fr + + exercises the ppzkSNARK (first generator, then prover, then verifier) on an R1CS instance with 1000 equations and an input consisting of 10 field elements. + + (If you get the error `zmInit ERR:can't protect`, see the discussion [above](#elliptic-curve-choices).) + + The command + + $ src/zk_proof_systems/ppzksnark/r1cs_gg_ppzksnark/profiling/profile_r1cs_gg_ppzksnark 1000 10 bytes + + does the same but now the input consists of 10 bytes. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ +#include +#include + +#include "common/default_types/r1cs_gg_ppzksnark_pp.hpp" +#include "common/profiling.hpp" +#include "common/utils.hpp" +#include "relations/constraint_satisfaction_problems/r1cs/examples/r1cs_examples.hpp" +#include "zk_proof_systems/ppzksnark/r1cs_gg_ppzksnark/examples/run_r1cs_gg_ppzksnark.hpp" + +using namespace libsnark; + +int main(int argc, const char * argv[]) +{ + default_r1cs_gg_ppzksnark_pp::init_public_params(); + start_profiling(); + + if (argc == 2 && strcmp(argv[1], "-v") == 0) + { + print_compilation_info(); + return 0; + } + + if (argc != 3 && argc != 4) + { + printf("usage: %s num_constraints input_size [Fr|bytes]\n", argv[0]); + return 1; + } + const int num_constraints = atoi(argv[1]); + int input_size = atoi(argv[2]); + if (argc == 4) + { + assert(strcmp(argv[3], "Fr") == 0 || strcmp(argv[3], "bytes") == 0); + if (strcmp(argv[3], "bytes") == 0) + { + input_size = div_ceil(8 * input_size, Fr::capacity()); + } + } + + enter_block("Generate R1CS example"); + r1cs_example > example = generate_r1cs_example_with_field_input >(num_constraints, input_size); + leave_block("Generate R1CS example"); + + print_header("(enter) Profile R1CS GG-ppzkSNARK"); + const bool test_serialization = true; + run_r1cs_gg_ppzksnark(example, test_serialization); + print_header("(leave) Profile R1CS GG-ppzkSNARK"); +} diff --git a/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/r1cs_gg_ppzksnark/r1cs_gg_ppzksnark.hpp b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/r1cs_gg_ppzksnark/r1cs_gg_ppzksnark.hpp new file mode 100644 index 0000000..3e997f6 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/r1cs_gg_ppzksnark/r1cs_gg_ppzksnark.hpp @@ -0,0 +1,448 @@ +/** @file +***************************************************************************** + +Declaration of interfaces for a ppzkSNARK for R1CS with a security proof +in the generic group (GG) model. + +This includes: +- class for proving key +- class for verification key +- class for processed verification key +- class for key pair (proving key & verification key) +- class for proof +- generator algorithm +- prover algorithm +- verifier algorithm (with strong or weak input consistency) +- online verifier algorithm (with strong or weak input consistency) + +The implementation instantiates the protocol of \[Gro16]. + + +Acronyms: + +- R1CS = "Rank-1 Constraint Systems" +- ppzkSNARK = "PreProcessing Zero-Knowledge Succinct Non-interactive ARgument of Knowledge" + +References: + +\[Gro16]: + "On the Size of Pairing-based Non-interactive Arguments", + Jens Groth, + EUROCRYPT 2016, + + + +***************************************************************************** +* @author This file is part of libsnark, developed by SCIPR Lab +* and contributors (see AUTHORS). +* @copyright MIT license (see LICENSE file) +*****************************************************************************/ + +#ifndef R1CS_GG_PPZKSNARK_HPP_ +#define R1CS_GG_PPZKSNARK_HPP_ + +#include + +#include "algebra/curves/public_params.hpp" +#include "common/data_structures/accumulation_vector.hpp" +#include "algebra/knowledge_commitment/knowledge_commitment.hpp" +#include "relations/constraint_satisfaction_problems/r1cs/r1cs.hpp" +#include "zk_proof_systems/ppzksnark/r1cs_gg_ppzksnark/r1cs_gg_ppzksnark_params.hpp" + +namespace libsnark { + +/******************************** Proving key ********************************/ + +template +class r1cs_gg_ppzksnark_proving_key; + +template +std::ostream& operator<<(std::ostream &out, const r1cs_gg_ppzksnark_proving_key &pk); + +template +std::istream& operator>>(std::istream &in, r1cs_gg_ppzksnark_proving_key &pk); + +/** + * A proving key for the R1CS GG-ppzkSNARK. + */ +template +class r1cs_gg_ppzksnark_proving_key { +public: + G1 delta_g1; + G2 delta_g2; + + G1_vector A_query; // this could be a sparse vector if we had multiexp for those + knowledge_commitment_vector, G1 > B_query; + G1_vector H_query; + G1_vector L_query; + + r1cs_gg_ppzksnark_constraint_system constraint_system; + + r1cs_gg_ppzksnark_proving_key() {}; + r1cs_gg_ppzksnark_proving_key& operator=(const r1cs_gg_ppzksnark_proving_key &other) = default; + r1cs_gg_ppzksnark_proving_key(const r1cs_gg_ppzksnark_proving_key &other) = default; + r1cs_gg_ppzksnark_proving_key(r1cs_gg_ppzksnark_proving_key &&other) = default; + r1cs_gg_ppzksnark_proving_key(G1 &&delta_g1, + G2 &&delta_g2, + G1_vector &&A_query, + knowledge_commitment_vector, G1 > &&B_query, + G1_vector &&H_query, + G1_vector &&L_query, + r1cs_gg_ppzksnark_constraint_system &&constraint_system) : + delta_g1(std::move(delta_g1)), + delta_g2(std::move(delta_g2)), + A_query(std::move(A_query)), + B_query(std::move(B_query)), + H_query(std::move(H_query)), + L_query(std::move(L_query)), + constraint_system(std::move(constraint_system)) + {}; + + size_t G1_size() const + { + return 1 + A_query.size() + B_query.domain_size() + H_query.size() + L_query.size(); + } + + size_t G2_size() const + { + return 1 + B_query.domain_size(); + } + + size_t G1_sparse_size() const + { + return 1 + A_query.size() + B_query.size() + H_query.size() + L_query.size(); + } + + size_t G2_sparse_size() const + { + return 1 + B_query.size(); + } + + size_t size_in_bits() const + { + return (libsnark::size_in_bits(A_query) + B_query.size_in_bits() + + libsnark::size_in_bits(H_query) + libsnark::size_in_bits(L_query) + + 1 * G1::size_in_bits() + 1 * G2::size_in_bits()); + } + + void print_size() const + { + print_indent(); printf("* G1 elements in PK: %zu\n", this->G1_size()); + print_indent(); printf("* Non-zero G1 elements in PK: %zu\n", this->G1_sparse_size()); + print_indent(); printf("* G2 elements in PK: %zu\n", this->G2_size()); + print_indent(); printf("* Non-zero G2 elements in PK: %zu\n", this->G2_sparse_size()); + print_indent(); printf("* PK size in bits: %zu\n", this->size_in_bits()); + } + + bool operator==(const r1cs_gg_ppzksnark_proving_key &other) const; + friend std::ostream& operator<< (std::ostream &out, const r1cs_gg_ppzksnark_proving_key &pk); + friend std::istream& operator>> (std::istream &in, r1cs_gg_ppzksnark_proving_key &pk); +}; + + +/******************************* Verification key ****************************/ + +template +class r1cs_gg_ppzksnark_verification_key; + +template +std::ostream& operator<<(std::ostream &out, const r1cs_gg_ppzksnark_verification_key &vk); + +template +std::istream& operator>>(std::istream &in, r1cs_gg_ppzksnark_verification_key &vk); + +/** + * A verification key for the R1CS GG-ppzkSNARK. + */ +template +class r1cs_gg_ppzksnark_verification_key { +public: + GT alpha_g1_beta_g2; + G2 gamma_g2; + G2 delta_g2; + + accumulation_vector > encoded_IC_query; + + r1cs_gg_ppzksnark_verification_key() = default; + r1cs_gg_ppzksnark_verification_key(const GT &alpha_g1_beta_g2, + const G2 &gamma_g2, + const G2 &delta_g2, + const accumulation_vector > &eIC) : + alpha_g1_beta_g2(alpha_g1_beta_g2), + gamma_g2(gamma_g2), + delta_g2(delta_g2), + encoded_IC_query(eIC) + {}; + + size_t G1_size() const + { + return encoded_IC_query.size(); + } + + size_t G2_size() const + { + return 2; + } + + size_t GT_size() const + { + return 1; + } + + size_t size_in_bits() const + { + // TODO: include GT size + return (encoded_IC_query.size_in_bits() + 2 * G2::size_in_bits()); + } + + void print_size() const + { + print_indent(); printf("* G1 elements in VK: %zu\n", this->G1_size()); + print_indent(); printf("* G2 elements in VK: %zu\n", this->G2_size()); + print_indent(); printf("* GT elements in VK: %zu\n", this->GT_size()); + print_indent(); printf("* VK size in bits: %zu\n", this->size_in_bits()); + } + + bool operator==(const r1cs_gg_ppzksnark_verification_key &other) const; + friend std::ostream& operator<< (std::ostream &out, const r1cs_gg_ppzksnark_verification_key &vk); + friend std::istream& operator>> (std::istream &in, r1cs_gg_ppzksnark_verification_key &vk); + + static r1cs_gg_ppzksnark_verification_key dummy_verification_key(const size_t input_size); +}; + + +/************************ Processed verification key *************************/ + +template +class r1cs_gg_ppzksnark_processed_verification_key; + +template +std::ostream& operator<<(std::ostream &out, const r1cs_gg_ppzksnark_processed_verification_key &pvk); + +template +std::istream& operator>>(std::istream &in, r1cs_gg_ppzksnark_processed_verification_key &pvk); + +/** + * A processed verification key for the R1CS GG-ppzkSNARK. + * + * Compared to a (non-processed) verification key, a processed verification key + * contains a small constant amount of additional pre-computed information that + * enables a faster verification time. + */ +template +class r1cs_gg_ppzksnark_processed_verification_key { +public: + GT vk_alpha_g1_beta_g2; + G2_precomp vk_gamma_g2_precomp; + G2_precomp vk_delta_g2_precomp; + + accumulation_vector > encoded_IC_query; + + bool operator==(const r1cs_gg_ppzksnark_processed_verification_key &other) const; + friend std::ostream& operator<< (std::ostream &out, const r1cs_gg_ppzksnark_processed_verification_key &pvk); + friend std::istream& operator>> (std::istream &in, r1cs_gg_ppzksnark_processed_verification_key &pvk); +}; + + +/********************************** Key pair *********************************/ + +/** + * A key pair for the R1CS GG-ppzkSNARK, which consists of a proving key and a verification key. + */ +template +class r1cs_gg_ppzksnark_keypair { +public: + r1cs_gg_ppzksnark_proving_key pk; + r1cs_gg_ppzksnark_verification_key vk; + + r1cs_gg_ppzksnark_keypair() = default; + r1cs_gg_ppzksnark_keypair(const r1cs_gg_ppzksnark_keypair &other) = default; + r1cs_gg_ppzksnark_keypair(r1cs_gg_ppzksnark_proving_key &&pk, + r1cs_gg_ppzksnark_verification_key &&vk) : + pk(std::move(pk)), + vk(std::move(vk)) + {} + + r1cs_gg_ppzksnark_keypair(r1cs_gg_ppzksnark_keypair &&other) = default; +}; + + +/*********************************** Proof ***********************************/ + +template +class r1cs_gg_ppzksnark_proof; + +template +std::ostream& operator<<(std::ostream &out, const r1cs_gg_ppzksnark_proof &proof); + +template +std::istream& operator>>(std::istream &in, r1cs_gg_ppzksnark_proof &proof); + +/** + * A proof for the R1CS GG-ppzkSNARK. + * + * While the proof has a structure, externally one merely opaquely produces, + * seralizes/deserializes, and verifies proofs. We only expose some information + * about the structure for statistics purposes. + */ +template +class r1cs_gg_ppzksnark_proof { +public: + G1 g_A; + G2 g_B; + G1 g_C; + + r1cs_gg_ppzksnark_proof() + { + // invalid proof with valid curve points + this->g_A = G1::one(); + this->g_B = G2::one(); + this->g_C = G1::one(); + } + r1cs_gg_ppzksnark_proof(G1 &&g_A, + G2 &&g_B, + G1 &&g_C) : + g_A(std::move(g_A)), + g_B(std::move(g_B)), + g_C(std::move(g_C)) + {}; + + size_t G1_size() const + { + return 2; + } + + size_t G2_size() const + { + return 1; + } + + size_t size_in_bits() const + { + return G1_size() * G1::size_in_bits() + G2_size() * G2::size_in_bits(); + } + + void print_size() const + { + print_indent(); printf("* G1 elements in proof: %zu\n", this->G1_size()); + print_indent(); printf("* G2 elements in proof: %zu\n", this->G2_size()); + print_indent(); printf("* Proof size in bits: %zu\n", this->size_in_bits()); + } + + bool is_well_formed() const + { + return (g_A.is_well_formed() && + g_B.is_well_formed() && + g_C.is_well_formed()); + } + + bool operator==(const r1cs_gg_ppzksnark_proof &other) const; + friend std::ostream& operator<< (std::ostream &out, const r1cs_gg_ppzksnark_proof &proof); + friend std::istream& operator>> (std::istream &in, r1cs_gg_ppzksnark_proof &proof); +}; + + +/***************************** Main algorithms *******************************/ + +/** + * A generator algorithm for the R1CS GG-ppzkSNARK. + * + * Given a R1CS constraint system CS, this algorithm produces proving and verification keys for CS. + */ +template +r1cs_gg_ppzksnark_keypair r1cs_gg_ppzksnark_generator(const r1cs_gg_ppzksnark_constraint_system &cs); + +/** + * A prover algorithm for the R1CS GG-ppzkSNARK. + * + * Given a R1CS primary input X and a R1CS auxiliary input Y, this algorithm + * produces a proof (of knowledge) that attests to the following statement: + * ``there exists Y such that CS(X,Y)=0''. + * Above, CS is the R1CS constraint system that was given as input to the generator algorithm. + */ +template +r1cs_gg_ppzksnark_proof r1cs_gg_ppzksnark_prover(const r1cs_gg_ppzksnark_proving_key &pk, + const r1cs_gg_ppzksnark_primary_input &primary_input, + const r1cs_gg_ppzksnark_auxiliary_input &auxiliary_input); + +/* + Below are four variants of verifier algorithm for the R1CS GG-ppzkSNARK. + + These are the four cases that arise from the following two choices: + + (1) The verifier accepts a (non-processed) verification key or, instead, a processed verification key. + In the latter case, we call the algorithm an "online verifier". + + (2) The verifier checks for "weak" input consistency or, instead, "strong" input consistency. + Strong input consistency requires that |primary_input| = CS.num_inputs, whereas + weak input consistency requires that |primary_input| <= CS.num_inputs (and + the primary input is implicitly padded with zeros up to length CS.num_inputs). +*/ + +/** + * A verifier algorithm for the R1CS GG-ppzkSNARK that: + * (1) accepts a non-processed verification key, and + * (2) has weak input consistency. + */ +template +bool r1cs_gg_ppzksnark_verifier_weak_IC(const r1cs_gg_ppzksnark_verification_key &vk, + const r1cs_gg_ppzksnark_primary_input &primary_input, + const r1cs_gg_ppzksnark_proof &proof); + +/** + * A verifier algorithm for the R1CS GG-ppzkSNARK that: + * (1) accepts a non-processed verification key, and + * (2) has strong input consistency. + */ +template +bool r1cs_gg_ppzksnark_verifier_strong_IC(const r1cs_gg_ppzksnark_verification_key &vk, + const r1cs_gg_ppzksnark_primary_input &primary_input, + const r1cs_gg_ppzksnark_proof &proof); + +/** + * Convert a (non-processed) verification key into a processed verification key. + */ +template +r1cs_gg_ppzksnark_processed_verification_key r1cs_gg_ppzksnark_verifier_process_vk(const r1cs_gg_ppzksnark_verification_key &vk); + +/** + * A verifier algorithm for the R1CS GG-ppzkSNARK that: + * (1) accepts a processed verification key, and + * (2) has weak input consistency. + */ +template +bool r1cs_gg_ppzksnark_online_verifier_weak_IC(const r1cs_gg_ppzksnark_processed_verification_key &pvk, + const r1cs_gg_ppzksnark_primary_input &input, + const r1cs_gg_ppzksnark_proof &proof); + +/** + * A verifier algorithm for the R1CS GG-ppzkSNARK that: + * (1) accepts a processed verification key, and + * (2) has strong input consistency. + */ +template +bool r1cs_gg_ppzksnark_online_verifier_strong_IC(const r1cs_gg_ppzksnark_processed_verification_key &pvk, + const r1cs_gg_ppzksnark_primary_input &primary_input, + const r1cs_gg_ppzksnark_proof &proof); + +/****************************** Miscellaneous ********************************/ + +/** + * For debugging purposes (of r1cs_gg_ppzksnark_r1cs_gg_ppzksnark_verifier_gadget): + * + * A verifier algorithm for the R1CS GG-ppzkSNARK that: + * (1) accepts a non-processed verification key, + * (2) has weak input consistency, and + * (3) uses affine coordinates for elliptic-curve computations. + */ +template +bool r1cs_gg_ppzksnark_affine_verifier_weak_IC(const r1cs_gg_ppzksnark_verification_key &vk, + const r1cs_gg_ppzksnark_primary_input &primary_input, + const r1cs_gg_ppzksnark_proof &proof); + + +} // libsnark + +#include "zk_proof_systems/ppzksnark/r1cs_gg_ppzksnark/r1cs_gg_ppzksnark.tcc" + +#endif // R1CS_GG_PPZKSNARK_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/r1cs_gg_ppzksnark/r1cs_gg_ppzksnark.tcc b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/r1cs_gg_ppzksnark/r1cs_gg_ppzksnark.tcc new file mode 100644 index 0000000..48ad1fb --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/r1cs_gg_ppzksnark/r1cs_gg_ppzksnark.tcc @@ -0,0 +1,626 @@ +/** @file +***************************************************************************** + +Implementation of interfaces for a ppzkSNARK for R1CS. + +See r1cs_gg_ppzksnark.hpp . + +***************************************************************************** +* @author This file is part of libsnark, developed by SCIPR Lab +* and contributors (see AUTHORS). +* @copyright MIT license (see LICENSE file) +*****************************************************************************/ + +#ifndef R1CS_GG_PPZKSNARK_TCC_ +#define R1CS_GG_PPZKSNARK_TCC_ + +#include +#include +#include +#include +#include + +#include "common/profiling.hpp" +#include "common/utils.hpp" +#include "algebra/scalar_multiplication/multiexp.hpp" +#include "algebra/scalar_multiplication/kc_multiexp.hpp" +#include "reductions/r1cs_to_qap/r1cs_to_qap.hpp" + +namespace libsnark { + +template +bool r1cs_gg_ppzksnark_proving_key::operator==(const r1cs_gg_ppzksnark_proving_key &other) const +{ + return (this->delta_g1 == other.delta_g1 && + this->delta_g2 == other.delta_g2 && + this->A_query == other.A_query && + this->B_query == other.B_query && + this->H_query == other.H_query && + this->L_query == other.L_query && + this->constraint_system == other.constraint_system); +} + +template +std::ostream& operator<<(std::ostream &out, const r1cs_gg_ppzksnark_proving_key &pk) +{ + out << pk.delta_g1 << OUTPUT_NEWLINE; + out << pk.delta_g2 << OUTPUT_NEWLINE; + out << pk.A_query; + out << pk.B_query; + out << pk.H_query; + out << pk.L_query; + out << pk.constraint_system; + + return out; +} + +template +std::istream& operator>>(std::istream &in, r1cs_gg_ppzksnark_proving_key &pk) +{ + in >> pk.delta_g1; + consume_OUTPUT_NEWLINE(in); + in >> pk.delta_g2; + consume_OUTPUT_NEWLINE(in); + in >> pk.A_query; + in >> pk.B_query; + in >> pk.H_query; + in >> pk.L_query; + in >> pk.constraint_system; + + return in; +} + +template +bool r1cs_gg_ppzksnark_verification_key::operator==(const r1cs_gg_ppzksnark_verification_key &other) const +{ + return (this->alpha_g1_beta_g2 == other.alpha_g1_beta_g2 && + this->gamma_g2 == other.gamma_g2 && + this->delta_g2 == other.delta_g2 && + this->encoded_IC_query == other.encoded_IC_query); +} + +template +std::ostream& operator<<(std::ostream &out, const r1cs_gg_ppzksnark_verification_key &vk) +{ + out << vk.alpha_g1_beta_g2 << OUTPUT_NEWLINE; + out << vk.gamma_g2 << OUTPUT_NEWLINE; + out << vk.delta_g2 << OUTPUT_NEWLINE; + out << vk.encoded_IC_query << OUTPUT_NEWLINE; + + return out; +} + +template +std::istream& operator>>(std::istream &in, r1cs_gg_ppzksnark_verification_key &vk) +{ + in >> vk.alpha_g1_beta_g2; + consume_OUTPUT_NEWLINE(in); + in >> vk.gamma_g2; + consume_OUTPUT_NEWLINE(in); + in >> vk.delta_g2; + consume_OUTPUT_NEWLINE(in); + in >> vk.encoded_IC_query; + consume_OUTPUT_NEWLINE(in); + + return in; +} + +template +bool r1cs_gg_ppzksnark_processed_verification_key::operator==(const r1cs_gg_ppzksnark_processed_verification_key &other) const +{ + return (this->vk_alpha_g1_beta_g2 == other.vk_alpha_g1_beta_g2 && + this->vk_gamma_g2_precomp == other.vk_gamma_g2_precomp && + this->vk_delta_g2_precomp == other.vk_delta_g2_precomp && + this->encoded_IC_query == other.encoded_IC_query); +} + +template +std::ostream& operator<<(std::ostream &out, const r1cs_gg_ppzksnark_processed_verification_key &pvk) +{ + out << pvk.vk_alpha_g1_beta_g2 << OUTPUT_NEWLINE; + out << pvk.vk_gamma_g2_precomp << OUTPUT_NEWLINE; + out << pvk.vk_delta_g2_precomp << OUTPUT_NEWLINE; + out << pvk.encoded_IC_query << OUTPUT_NEWLINE; + + return out; +} + +template +std::istream& operator>>(std::istream &in, r1cs_gg_ppzksnark_processed_verification_key &pvk) +{ + in >> pvk.vk_alpha_g1_beta_g2; + consume_OUTPUT_NEWLINE(in); + in >> pvk.vk_gamma_g2_precomp; + consume_OUTPUT_NEWLINE(in); + in >> pvk.vk_delta_g2_precomp; + consume_OUTPUT_NEWLINE(in); + in >> pvk.encoded_IC_query; + consume_OUTPUT_NEWLINE(in); + + return in; +} + +template +bool r1cs_gg_ppzksnark_proof::operator==(const r1cs_gg_ppzksnark_proof &other) const +{ + return (this->g_A == other.g_A && + this->g_B == other.g_B && + this->g_C == other.g_C); +} + +template +std::ostream& operator<<(std::ostream &out, const r1cs_gg_ppzksnark_proof &proof) +{ + out << proof.g_A << OUTPUT_NEWLINE; + out << proof.g_B << OUTPUT_NEWLINE; + out << proof.g_C << OUTPUT_NEWLINE; + + return out; +} + +template +std::istream& operator>>(std::istream &in, r1cs_gg_ppzksnark_proof &proof) +{ + in >> proof.g_A; + consume_OUTPUT_NEWLINE(in); + in >> proof.g_B; + consume_OUTPUT_NEWLINE(in); + in >> proof.g_C; + consume_OUTPUT_NEWLINE(in); + + return in; +} + +template +r1cs_gg_ppzksnark_verification_key r1cs_gg_ppzksnark_verification_key::dummy_verification_key(const size_t input_size) +{ + r1cs_gg_ppzksnark_verification_key result; + result.alpha_g1_beta_g2 = Fr::random_element() * GT::random_element(); + result.gamma_g2 = G2::random_element(); + result.delta_g2 = G2::random_element(); + + G1 base = G1::random_element(); + G1_vector v; + for (size_t i = 0; i < input_size; ++i) + { + v.emplace_back(G1::random_element()); + } + + result.encoded_IC_query = accumulation_vector >(std::move(base), std::move(v)); + + return result; +} + +template +r1cs_gg_ppzksnark_keypair r1cs_gg_ppzksnark_generator(const r1cs_gg_ppzksnark_constraint_system &cs) +{ + enter_block("Call to r1cs_gg_ppzksnark_generator"); + + /* make the B_query "lighter" if possible */ + r1cs_gg_ppzksnark_constraint_system cs_copy(cs); + cs_copy.swap_AB_if_beneficial(); + + /* draw random element at which the QAP is evaluated */ + const Fr t = Fr::random_element(); + + qap_instance_evaluation > qap_inst = r1cs_to_qap_instance_map_with_evaluation(cs_copy, t); + + print_indent(); printf("* QAP number of variables: %zu\n", qap_inst.num_variables()); + print_indent(); printf("* QAP pre degree: %zu\n", cs_copy.constraints.size()); + print_indent(); printf("* QAP degree: %zu\n", qap_inst.degree()); + print_indent(); printf("* QAP number of input variables: %zu\n", qap_inst.num_inputs()); + + enter_block("Compute query densities"); + size_t non_zero_At = 0, non_zero_Bt = 0; + for (size_t i = 0; i < qap_inst.num_variables()+1; ++i) + { + if (!qap_inst.At[i].is_zero()) + { + ++non_zero_At; + } + if (!qap_inst.Bt[i].is_zero()) + { + ++non_zero_Bt; + } + } + leave_block("Compute query densities"); + + /* qap_inst.{At,Bt,Ct,Ht} are now in unspecified state, but we do not use them later */ + Fr_vector At = std::move(qap_inst.At); + Fr_vector Bt = std::move(qap_inst.Bt); + Fr_vector Ct = std::move(qap_inst.Ct); + Fr_vector Ht = std::move(qap_inst.Ht); + + const Fr alpha = Fr::random_element(), + beta = Fr::random_element(), + gamma = Fr::random_element(), + delta = Fr::random_element(); + + /* append \alpha and \beta to At and Bt */ + At.emplace_back(alpha); ++non_zero_At; + Bt.emplace_back(beta); ++non_zero_Bt; + + /* construct IC coefficients */ + Fr_vector IC_input_coefficients; + IC_input_coefficients.reserve(qap_inst.num_inputs()); + const Fr gamma_inverse = gamma.inverse(); + + const Fr IC_constant_coefficient = (beta * At[0] + alpha * Bt[0] + Ct[0]) * gamma_inverse; + for (size_t i = 1; i < qap_inst.num_inputs() + 1; ++i) + { + IC_input_coefficients.emplace_back((beta * At[i] + alpha * Bt[i] + Ct[i]) * gamma_inverse); + } + + /* construct L query */ + Fr_vector Lt; + Lt.reserve(qap_inst.num_variables() - qap_inst.num_inputs()); + + const Fr delta_inverse = delta.inverse(); + const size_t Lt_offset = qap_inst.num_inputs() + 1; + for (size_t i = 0; i < qap_inst.num_variables() - qap_inst.num_inputs(); ++i) + { + Lt.emplace_back((beta * At[Lt_offset + i] + alpha * Bt[Lt_offset + i] + Ct[Lt_offset + i]) * delta_inverse); + } + + /* Note that H for Groth's proof system is degree d-2, but the QAP + reduction returns coefficients for degree d polynomial H (in + style of PGHR-type proof systems) */ + Ht.resize(Ht.size() - 2); + + const size_t g1_exp_count = non_zero_At + non_zero_Bt + qap_inst.num_variables(); + const size_t g2_exp_count = non_zero_Bt; + + size_t g1_window = get_exp_window_size >(g1_exp_count); + size_t g2_window = get_exp_window_size >(g2_exp_count); + print_indent(); printf("* G1 window: %zu\n", g1_window); + print_indent(); printf("* G2 window: %zu\n", g2_window); + +#ifdef MULTICORE + const size_t chunks = omp_get_max_threads(); // to override, set OMP_NUM_THREADS env var or call omp_set_num_threads() +#else + const size_t chunks = 1; +#endif + + const G1 G1_gen = G1::random_element(); + const G2 G2_gen = G2::random_element(); + + enter_block("Generating G1 multiexp table"); + window_table > g1_table = get_window_table(Fr::size_in_bits(), g1_window, G1_gen); + leave_block("Generating G1 multiexp table"); + + enter_block("Generating G2 multiexp table"); + window_table > g2_table = get_window_table(Fr::size_in_bits(), g2_window, G2_gen); + leave_block("Generating G2 multiexp table"); + + enter_block("Generate R1CS proving key"); + G1 delta_g1 = delta * G1_gen; + G2 delta_g2 = delta * G2_gen; + + enter_block("Generate queries"); + enter_block("Compute the A-query", false); + G1_vector A_query = batch_exp(Fr::size_in_bits(), g1_window, g1_table, At); +#ifdef USE_MIXED_ADDITION + batch_to_special >(A_query); +#endif + leave_block("Compute the A-query", false); + + enter_block("Compute the B-query", false); + knowledge_commitment_vector, G1 > B_query = kc_batch_exp(Fr::size_in_bits(), g2_window, g1_window, g2_table, g1_table, Fr::one(), Fr::one(), Bt, chunks); + leave_block("Compute the B-query", false); + + enter_block("Compute the H-query", false); + G1_vector H_query = batch_exp_with_coeff(Fr::size_in_bits(), g1_window, g1_table, qap_inst.Zt * delta_inverse, Ht); + leave_block("Compute the H-query", false); + + enter_block("Compute the L-query", false); + G1_vector L_query = batch_exp(Fr::size_in_bits(), g1_window, g1_table, Lt); +#ifdef USE_MIXED_ADDITION + batch_to_special >(L_query); +#endif + leave_block("Compute the L-query", false); + leave_block("Generate queries"); + + leave_block("Generate R1CS proving key"); + + enter_block("Generate R1CS verification key"); + GT alpha_g1_beta_g2 = ppT::reduced_pairing(alpha * G1_gen, beta * G2_gen); + G2 gamma_g2 = gamma * G2_gen; + + enter_block("Encode IC query for R1CS verification key"); + G1 encoded_IC_base = IC_constant_coefficient * G1_gen; + G1_vector encoded_IC_values = batch_exp(Fr::size_in_bits(), g1_window, g1_table, + IC_input_coefficients); + leave_block("Encode IC query for R1CS verification key"); + leave_block("Generate R1CS verification key"); + + leave_block("Call to r1cs_gg_ppzksnark_generator"); + + accumulation_vector > encoded_IC_query(std::move(encoded_IC_base), std::move(encoded_IC_values)); + + r1cs_gg_ppzksnark_verification_key vk = r1cs_gg_ppzksnark_verification_key(alpha_g1_beta_g2, + gamma_g2, + delta_g2, + encoded_IC_query); + + r1cs_gg_ppzksnark_proving_key pk = r1cs_gg_ppzksnark_proving_key(std::move(delta_g1), + std::move(delta_g2), + std::move(A_query), + std::move(B_query), + std::move(H_query), + std::move(L_query), + std::move(cs_copy)); + + pk.print_size(); + vk.print_size(); + + return r1cs_gg_ppzksnark_keypair(std::move(pk), std::move(vk)); +} + +template +r1cs_gg_ppzksnark_proof r1cs_gg_ppzksnark_prover(const r1cs_gg_ppzksnark_proving_key &pk, + const r1cs_gg_ppzksnark_primary_input &primary_input, + const r1cs_gg_ppzksnark_auxiliary_input &auxiliary_input) +{ + enter_block("Call to r1cs_gg_ppzksnark_prover"); + +#ifdef DEBUG + assert(pk.constraint_system.is_satisfied(primary_input, auxiliary_input)); +#endif + + enter_block("Compute the polynomial H"); + const qap_witness > qap_wit = r1cs_to_qap_witness_map(pk.constraint_system, primary_input, auxiliary_input, Fr::zero(), Fr::zero(), Fr::zero()); + + /* We are dividing degree 2(d-1) polynomial by degree d polynomial + and not adding a PGHR-style ZK-patch, so our H is degree d-2 */ + assert(!qap_wit.coefficients_for_H[qap_wit.degree()-2].is_zero()); + assert(qap_wit.coefficients_for_H[qap_wit.degree()-1].is_zero()); + assert(qap_wit.coefficients_for_H[qap_wit.degree()].is_zero()); + leave_block("Compute the polynomial H"); + +#ifdef DEBUG + const Fr t = Fr::random_element(); + qap_instance_evaluation > qap_inst = r1cs_to_qap_instance_map_with_evaluation(pk.constraint_system, t); + assert(qap_inst.is_satisfied(qap_wit)); +#endif + + const Fr r = Fr::random_element(); + const Fr s = Fr::random_element(); + G1 g_A = r * pk.delta_g1 + pk.A_query[qap_wit.num_variables()+1]; + G2 g_B = s * pk.delta_g2 + pk.B_query[qap_wit.num_variables()+1].g; // TODO: swap g and h in knowledge commitment + G1 g_C = (r * s) * pk.delta_g1 + s * pk.A_query[qap_wit.num_variables()+1] + r * pk.B_query[qap_wit.num_variables()+1].h; + +#ifdef DEBUG + assert(qap_wit.coefficients_for_ABCs.size() == qap_wit.num_variables()); + assert(pk.A_query.size() == qap_wit.num_variables()+2); + assert(pk.B_query.domain_size() == qap_wit.num_variables()+2); + assert(pk.H_query.size() == qap_wit.degree() - 1); + assert(pk.L_query.size() == qap_wit.num_variables() - qap_wit.num_inputs()); +#endif + +#ifdef MULTICORE + const size_t chunks = omp_get_max_threads(); // to override, set OMP_NUM_THREADS env var or call omp_set_num_threads() +#else + const size_t chunks = 1; +#endif + + enter_block("Compute the proof"); + + enter_block("Compute answer to A-query", false); + // TODO: sort out indexing + Fr_vector const_padded_assignment(1, Fr::one()); + const_padded_assignment.insert(const_padded_assignment.end(), qap_wit.coefficients_for_ABCs.begin(), qap_wit.coefficients_for_ABCs.end()); + + G1 A_answer = multi_exp_with_mixed_addition, Fr >(pk.A_query.begin(), pk.A_query.begin() + qap_wit.num_variables() + 1, + const_padded_assignment.begin(), const_padded_assignment.begin() + qap_wit.num_variables() + 1, + chunks, true); + g_A = g_A + A_answer; + g_C = g_C + s * A_answer; + leave_block("Compute answer to A-query", false); + + enter_block("Compute answer to B-query", false); + knowledge_commitment, G1 > B_answer; + B_answer = kc_multi_exp_with_mixed_addition, G1, Fr >(pk.B_query, + 0, qap_wit.num_variables() + 1, + const_padded_assignment.begin(), const_padded_assignment.begin() + qap_wit.num_variables() + 1, + chunks, true); + g_B = g_B + B_answer.g; + g_C = g_C + r * B_answer.h; + leave_block("Compute answer to B-query", false); + + enter_block("Compute answer to H-query", false); + g_C = g_C + multi_exp, Fr >(pk.H_query.begin(), pk.H_query.begin() + (qap_wit.degree() - 1), + qap_wit.coefficients_for_H.begin(), qap_wit.coefficients_for_H.begin() + (qap_wit.degree() - 1), + chunks, true); + leave_block("Compute answer to H-query", false); + + enter_block("Compute answer to L-query", false); + g_C = g_C + multi_exp_with_mixed_addition, Fr >(pk.L_query.begin(), pk.L_query.end(), + const_padded_assignment.begin()+qap_wit.num_inputs()+1, const_padded_assignment.begin()+qap_wit.num_variables()+1, + chunks, true); + leave_block("Compute answer to L-query", false); + + leave_block("Compute the proof"); + + leave_block("Call to r1cs_gg_ppzksnark_prover"); + + r1cs_gg_ppzksnark_proof proof = r1cs_gg_ppzksnark_proof(std::move(g_A), std::move(g_B), std::move(g_C)); + proof.print_size(); + + return proof; +} + +template +r1cs_gg_ppzksnark_processed_verification_key r1cs_gg_ppzksnark_verifier_process_vk(const r1cs_gg_ppzksnark_verification_key &vk) +{ + enter_block("Call to r1cs_gg_ppzksnark_verifier_process_vk"); + + r1cs_gg_ppzksnark_processed_verification_key pvk; + pvk.vk_alpha_g1_beta_g2 = vk.alpha_g1_beta_g2; + pvk.vk_gamma_g2_precomp = ppT::precompute_G2(vk.gamma_g2); + pvk.vk_delta_g2_precomp = ppT::precompute_G2(vk.delta_g2); + pvk.encoded_IC_query = vk.encoded_IC_query; + + leave_block("Call to r1cs_gg_ppzksnark_verifier_process_vk"); + + return pvk; +} + +template +bool r1cs_gg_ppzksnark_online_verifier_weak_IC(const r1cs_gg_ppzksnark_processed_verification_key &pvk, + const r1cs_gg_ppzksnark_primary_input &primary_input, + const r1cs_gg_ppzksnark_proof &proof) +{ + enter_block("Call to r1cs_gg_ppzksnark_online_verifier_weak_IC"); + assert(pvk.encoded_IC_query.domain_size() >= primary_input.size()); + + enter_block("Accumulate input"); + const accumulation_vector > accumulated_IC = pvk.encoded_IC_query.template accumulate_chunk >(primary_input.begin(), primary_input.end(), 0); + const G1 &acc = accumulated_IC.first; + leave_block("Accumulate input"); + + bool result = true; + + enter_block("Check if the proof is well-formed"); + if (!proof.is_well_formed()) + { + if (!inhibit_profiling_info) + { + print_indent(); printf("At least one of the proof elements does not lie on the curve.\n"); + } + result = false; + } + leave_block("Check if the proof is well-formed"); + + enter_block("Online pairing computations"); + enter_block("Check QAP divisibility"); + const G1_precomp proof_g_A_precomp = ppT::precompute_G1(proof.g_A); + const G2_precomp proof_g_B_precomp = ppT::precompute_G2(proof.g_B); + const G1_precomp proof_g_C_precomp = ppT::precompute_G1(proof.g_C); + const G1_precomp acc_precomp = ppT::precompute_G1(acc); + + const Fqk QAP1 = ppT::miller_loop(proof_g_A_precomp, proof_g_B_precomp); + const Fqk QAP2 = ppT::double_miller_loop( + acc_precomp, pvk.vk_gamma_g2_precomp, + proof_g_C_precomp, pvk.vk_delta_g2_precomp); + const GT QAP = ppT::final_exponentiation(QAP1 * QAP2.unitary_inverse()); + + if (QAP != pvk.vk_alpha_g1_beta_g2) + { + if (!inhibit_profiling_info) + { + print_indent(); printf("QAP divisibility check failed.\n"); + } + result = false; + } + leave_block("Check QAP divisibility"); + leave_block("Online pairing computations"); + + leave_block("Call to r1cs_gg_ppzksnark_online_verifier_weak_IC"); + + return result; +} + +template +bool r1cs_gg_ppzksnark_verifier_weak_IC(const r1cs_gg_ppzksnark_verification_key &vk, + const r1cs_gg_ppzksnark_primary_input &primary_input, + const r1cs_gg_ppzksnark_proof &proof) +{ + enter_block("Call to r1cs_gg_ppzksnark_verifier_weak_IC"); + r1cs_gg_ppzksnark_processed_verification_key pvk = r1cs_gg_ppzksnark_verifier_process_vk(vk); + bool result = r1cs_gg_ppzksnark_online_verifier_weak_IC(pvk, primary_input, proof); + leave_block("Call to r1cs_gg_ppzksnark_verifier_weak_IC"); + return result; +} + +template +bool r1cs_gg_ppzksnark_online_verifier_strong_IC(const r1cs_gg_ppzksnark_processed_verification_key &pvk, + const r1cs_gg_ppzksnark_primary_input &primary_input, + const r1cs_gg_ppzksnark_proof &proof) +{ + bool result = true; + enter_block("Call to r1cs_gg_ppzksnark_online_verifier_strong_IC"); + + if (pvk.encoded_IC_query.domain_size() != primary_input.size()) + { + print_indent(); printf("Input length differs from expected (got %zu, expected %zu).\n", primary_input.size(), pvk.encoded_IC_query.domain_size()); + result = false; + } + else + { + result = r1cs_gg_ppzksnark_online_verifier_weak_IC(pvk, primary_input, proof); + } + + leave_block("Call to r1cs_gg_ppzksnark_online_verifier_strong_IC"); + return result; +} + +template +bool r1cs_gg_ppzksnark_verifier_strong_IC(const r1cs_gg_ppzksnark_verification_key &vk, + const r1cs_gg_ppzksnark_primary_input &primary_input, + const r1cs_gg_ppzksnark_proof &proof) +{ + enter_block("Call to r1cs_gg_ppzksnark_verifier_strong_IC"); + r1cs_gg_ppzksnark_processed_verification_key pvk = r1cs_gg_ppzksnark_verifier_process_vk(vk); + bool result = r1cs_gg_ppzksnark_online_verifier_strong_IC(pvk, primary_input, proof); + leave_block("Call to r1cs_gg_ppzksnark_verifier_strong_IC"); + return result; +} + +template +bool r1cs_gg_ppzksnark_affine_verifier_weak_IC(const r1cs_gg_ppzksnark_verification_key &vk, + const r1cs_gg_ppzksnark_primary_input &primary_input, + const r1cs_gg_ppzksnark_proof &proof) +{ + enter_block("Call to r1cs_gg_ppzksnark_affine_verifier_weak_IC"); + assert(vk.encoded_IC_query.domain_size() >= primary_input.size()); + + affine_ate_G2_precomp pvk_vk_gamma_g2_precomp = ppT::affine_ate_precompute_G2(vk.gamma_g2); + affine_ate_G2_precomp pvk_vk_delta_g2_precomp = ppT::affine_ate_precompute_G2(vk.delta_g2); + + enter_block("Accumulate input"); + const accumulation_vector > accumulated_IC = vk.encoded_IC_query.template accumulate_chunk >(primary_input.begin(), primary_input.end(), 0); + const G1 &acc = accumulated_IC.first; + leave_block("Accumulate input"); + + bool result = true; + + enter_block("Check if the proof is well-formed"); + if (!proof.is_well_formed()) + { + if (!inhibit_profiling_info) + { + print_indent(); printf("At least one of the proof elements does not lie on the curve.\n"); + } + result = false; + } + leave_block("Check if the proof is well-formed"); + + enter_block("Check QAP divisibility"); + const affine_ate_G1_precomp proof_g_A_precomp = ppT::affine_ate_precompute_G1(proof.g_A); + const affine_ate_G2_precomp proof_g_B_precomp = ppT::affine_ate_precompute_G2(proof.g_B); + const affine_ate_G1_precomp proof_g_C_precomp = ppT::affine_ate_precompute_G1(proof.g_C); + const affine_ate_G1_precomp acc_precomp = ppT::affine_ate_precompute_G1(acc); + + const Fqk QAP_miller = ppT::affine_ate_e_times_e_over_e_miller_loop( + acc_precomp, pvk_vk_gamma_g2_precomp, + proof_g_C_precomp, pvk_vk_delta_g2_precomp, + proof_g_A_precomp, proof_g_B_precomp); + const GT QAP = ppT::final_exponentiation(QAP_miller.unitary_inverse()); + + if (QAP != vk.alpha_g1_beta_g2) + { + if (!inhibit_profiling_info) + { + print_indent(); printf("QAP divisibility check failed.\n"); + } + result = false; + } + leave_block("Check QAP divisibility"); + + leave_block("Call to r1cs_gg_ppzksnark_affine_verifier_weak_IC"); + + return result; +} + +} // libsnark +#endif // R1CS_GG_PPZKSNARK_TCC_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/r1cs_gg_ppzksnark/r1cs_gg_ppzksnark_params.hpp b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/r1cs_gg_ppzksnark/r1cs_gg_ppzksnark_params.hpp new file mode 100644 index 0000000..dd347cb --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/r1cs_gg_ppzksnark/r1cs_gg_ppzksnark_params.hpp @@ -0,0 +1,34 @@ +/** @file + ***************************************************************************** + + Declaration of public-parameter selector for the R1CS GG-ppzkSNARK. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef R1CS_GG_PPZKSNARK_PARAMS_HPP_ +#define R1CS_GG_PPZKSNARK_PARAMS_HPP_ + +#include "relations/constraint_satisfaction_problems/r1cs/r1cs.hpp" + +namespace libsnark { + +/** + * Below are various template aliases (used for convenience). + */ + +template +using r1cs_gg_ppzksnark_constraint_system = r1cs_constraint_system >; + +template +using r1cs_gg_ppzksnark_primary_input = r1cs_primary_input >; + +template +using r1cs_gg_ppzksnark_auxiliary_input = r1cs_auxiliary_input >; + +} // libsnark + +#endif // R1CS_GG_PPZKSNARK_PARAMS_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/r1cs_gg_ppzksnark/tests/test_r1cs_gg_ppzksnark.cpp b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/r1cs_gg_ppzksnark/tests/test_r1cs_gg_ppzksnark.cpp new file mode 100644 index 0000000..c2e0906 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/r1cs_gg_ppzksnark/tests/test_r1cs_gg_ppzksnark.cpp @@ -0,0 +1,42 @@ +/** @file + ***************************************************************************** + Test program that exercises the ppzkSNARK (first generator, then + prover, then verifier) on a synthetic R1CS instance. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ +#include +#include + +#include "common/default_types/r1cs_gg_ppzksnark_pp.hpp" +#include "common/profiling.hpp" +#include "common/utils.hpp" +#include "relations/constraint_satisfaction_problems/r1cs/examples/r1cs_examples.hpp" +#include "zk_proof_systems/ppzksnark/r1cs_gg_ppzksnark/examples/run_r1cs_gg_ppzksnark.hpp" + +using namespace libsnark; + +template +void test_r1cs_gg_ppzksnark(size_t num_constraints, + size_t input_size) +{ + print_header("(enter) Test R1CS GG-ppzkSNARK"); + + const bool test_serialization = true; + r1cs_example > example = generate_r1cs_example_with_binary_input >(num_constraints, input_size); + const bool bit = run_r1cs_gg_ppzksnark(example, test_serialization); + assert(bit); + + print_header("(leave) Test R1CS GG-ppzkSNARK"); +} + +int main() +{ + default_r1cs_gg_ppzksnark_pp::init_public_params(); + start_profiling(); + + test_r1cs_gg_ppzksnark(1000, 100); +} diff --git a/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/examples/run_r1cs_ppzksnark.hpp b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/examples/run_r1cs_ppzksnark.hpp new file mode 100644 index 0000000..d2a686c --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/examples/run_r1cs_ppzksnark.hpp @@ -0,0 +1,36 @@ +/** @file + ***************************************************************************** + + Declaration of functionality that runs the R1CS ppzkSNARK for + a given R1CS example. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef RUN_R1CS_PPZKSNARK_HPP_ +#define RUN_R1CS_PPZKSNARK_HPP_ + +#include "common/default_types/ec_pp.hpp" +#include "relations/constraint_satisfaction_problems/r1cs/examples/r1cs_examples.hpp" + +namespace libsnark { + +/** + * Runs the ppzkSNARK (generator, prover, and verifier) for a given + * R1CS example (specified by a constraint system, input, and witness). + * + * Optionally, also test the serialization routines for keys and proofs. + * (This takes additional time.) + */ +template +bool run_r1cs_ppzksnark(const r1cs_example > &example, + const bool test_serialization); + +} // libsnark + +#include "zk_proof_systems/ppzksnark/r1cs_ppzksnark/examples/run_r1cs_ppzksnark.tcc" + +#endif // RUN_R1CS_PPZKSNARK_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/examples/run_r1cs_ppzksnark.tcc b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/examples/run_r1cs_ppzksnark.tcc new file mode 100644 index 0000000..9bc8758 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/examples/run_r1cs_ppzksnark.tcc @@ -0,0 +1,114 @@ +/** @file + ***************************************************************************** + + Implementation of functionality that runs the R1CS ppzkSNARK for + a given R1CS example. + + See run_r1cs_ppzksnark.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef RUN_R1CS_PPZKSNARK_TCC_ +#define RUN_R1CS_PPZKSNARK_TCC_ + +#include "zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.hpp" + +#include +#include + +#include "common/profiling.hpp" + +namespace libsnark { + +template +typename std::enable_if::type +test_affine_verifier(const r1cs_ppzksnark_verification_key &vk, + const r1cs_ppzksnark_primary_input &primary_input, + const r1cs_ppzksnark_proof &proof, + const bool expected_answer) +{ + print_header("R1CS ppzkSNARK Affine Verifier"); + const bool answer = r1cs_ppzksnark_affine_verifier_weak_IC(vk, primary_input, proof); + assert(answer == expected_answer); +} + +template +typename std::enable_if::type +test_affine_verifier(const r1cs_ppzksnark_verification_key &vk, + const r1cs_ppzksnark_primary_input &primary_input, + const r1cs_ppzksnark_proof &proof, + const bool expected_answer) +{ + UNUSED(vk, primary_input, proof, expected_answer); + print_header("R1CS ppzkSNARK Affine Verifier"); + printf("Affine verifier is not supported; not testing anything.\n"); +} + +/** + * The code below provides an example of all stages of running a R1CS ppzkSNARK. + * + * Of course, in a real-life scenario, we would have three distinct entities, + * mangled into one in the demonstration below. The three entities are as follows. + * (1) The "generator", which runs the ppzkSNARK generator on input a given + * constraint system CS to create a proving and a verification key for CS. + * (2) The "prover", which runs the ppzkSNARK prover on input the proving key, + * a primary input for CS, and an auxiliary input for CS. + * (3) The "verifier", which runs the ppzkSNARK verifier on input the verification key, + * a primary input for CS, and a proof. + */ +template +bool run_r1cs_ppzksnark(const r1cs_example > &example, + const bool test_serialization) +{ + enter_block("Call to run_r1cs_ppzksnark"); + + print_header("R1CS ppzkSNARK Generator"); + r1cs_ppzksnark_keypair keypair = r1cs_ppzksnark_generator(example.constraint_system); + printf("\n"); print_indent(); print_mem("after generator"); + + print_header("Preprocess verification key"); + r1cs_ppzksnark_processed_verification_key pvk = r1cs_ppzksnark_verifier_process_vk(keypair.vk); + + if (test_serialization) + { + enter_block("Test serialization of keys"); + keypair.pk = reserialize >(keypair.pk); + keypair.vk = reserialize >(keypair.vk); + pvk = reserialize >(pvk); + leave_block("Test serialization of keys"); + } + + print_header("R1CS ppzkSNARK Prover"); + r1cs_ppzksnark_proof proof = r1cs_ppzksnark_prover(keypair.pk, example.primary_input, example.auxiliary_input); + printf("\n"); print_indent(); print_mem("after prover"); + + if (test_serialization) + { + enter_block("Test serialization of proof"); + proof = reserialize >(proof); + leave_block("Test serialization of proof"); + } + + print_header("R1CS ppzkSNARK Verifier"); + const bool ans = r1cs_ppzksnark_verifier_strong_IC(keypair.vk, example.primary_input, proof); + printf("\n"); print_indent(); print_mem("after verifier"); + printf("* The verification result is: %s\n", (ans ? "PASS" : "FAIL")); + + print_header("R1CS ppzkSNARK Online Verifier"); + const bool ans2 = r1cs_ppzksnark_online_verifier_strong_IC(pvk, example.primary_input, proof); + assert(ans == ans2); + + test_affine_verifier(keypair.vk, example.primary_input, proof, ans); + + leave_block("Call to run_r1cs_ppzksnark"); + + return ans; +} + +} // libsnark + +#endif // RUN_R1CS_PPZKSNARK_TCC_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/profiling/profile_r1cs_ppzksnark.cpp b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/profiling/profile_r1cs_ppzksnark.cpp new file mode 100644 index 0000000..5c54150 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/profiling/profile_r1cs_ppzksnark.cpp @@ -0,0 +1,71 @@ +/** @file + ***************************************************************************** + Profiling program that exercises the ppzkSNARK (first generator, then prover, + then verifier) on a synthetic R1CS instance. + + The command + + $ src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/profiling/profile_r1cs_ppzksnark 1000 10 Fr + + exercises the ppzkSNARK (first generator, then prover, then verifier) on an R1CS instance with 1000 equations and an input consisting of 10 field elements. + + (If you get the error `zmInit ERR:can't protect`, see the discussion [above](#elliptic-curve-choices).) + + The command + + $ src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/profiling/profile_r1cs_ppzksnark 1000 10 bytes + + does the same but now the input consists of 10 bytes. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ +#include +#include + +#include "common/default_types/r1cs_ppzksnark_pp.hpp" +#include "common/profiling.hpp" +#include "common/utils.hpp" +#include "relations/constraint_satisfaction_problems/r1cs/examples/r1cs_examples.hpp" +#include "zk_proof_systems/ppzksnark/r1cs_ppzksnark/examples/run_r1cs_ppzksnark.hpp" + +using namespace libsnark; + +int main(int argc, const char * argv[]) +{ + default_r1cs_ppzksnark_pp::init_public_params(); + start_profiling(); + + if (argc == 2 && strcmp(argv[1], "-v") == 0) + { + print_compilation_info(); + return 0; + } + + if (argc != 3 && argc != 4) + { + printf("usage: %s num_constraints input_size [Fr|bytes]\n", argv[0]); + return 1; + } + const int num_constraints = atoi(argv[1]); + int input_size = atoi(argv[2]); + if (argc == 4) + { + assert(strcmp(argv[3], "Fr") == 0 || strcmp(argv[3], "bytes") == 0); + if (strcmp(argv[3], "bytes") == 0) + { + input_size = div_ceil(8 * input_size, Fr::capacity()); + } + } + + enter_block("Generate R1CS example"); + r1cs_example > example = generate_r1cs_example_with_field_input >(num_constraints, input_size); + leave_block("Generate R1CS example"); + + print_header("(enter) Profile R1CS ppzkSNARK"); + const bool test_serialization = true; + run_r1cs_ppzksnark(example, test_serialization); + print_header("(leave) Profile R1CS ppzkSNARK"); +} diff --git a/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.hpp b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.hpp new file mode 100644 index 0000000..6e74f07 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.hpp @@ -0,0 +1,467 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for a ppzkSNARK for R1CS. + + This includes: + - class for proving key + - class for verification key + - class for processed verification key + - class for key pair (proving key & verification key) + - class for proof + - generator algorithm + - prover algorithm + - verifier algorithm (with strong or weak input consistency) + - online verifier algorithm (with strong or weak input consistency) + + The implementation instantiates (a modification of) the protocol of \[PGHR13], + by following extending, and optimizing the approach described in \[BCTV14]. + + + Acronyms: + + - R1CS = "Rank-1 Constraint Systems" + - ppzkSNARK = "PreProcessing Zero-Knowledge Succinct Non-interactive ARgument of Knowledge" + + References: + + \[BCTV14]: + "Succinct Non-Interactive Zero Knowledge for a von Neumann Architecture", + Eli Ben-Sasson, Alessandro Chiesa, Eran Tromer, Madars Virza, + USENIX Security 2014, + + + \[PGHR13]: + "Pinocchio: Nearly practical verifiable computation", + Bryan Parno, Craig Gentry, Jon Howell, Mariana Raykova, + IEEE S&P 2013, + + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef R1CS_PPZKSNARK_HPP_ +#define R1CS_PPZKSNARK_HPP_ + +#include + +#include "algebra/curves/public_params.hpp" +#include "common/data_structures/accumulation_vector.hpp" +#include "algebra/knowledge_commitment/knowledge_commitment.hpp" +#include "relations/constraint_satisfaction_problems/r1cs/r1cs.hpp" +#include "zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark_params.hpp" + +namespace libsnark { + +/******************************** Proving key ********************************/ + +template +class r1cs_ppzksnark_proving_key; + +template +std::ostream& operator<<(std::ostream &out, const r1cs_ppzksnark_proving_key &pk); + +template +std::istream& operator>>(std::istream &in, r1cs_ppzksnark_proving_key &pk); + +/** + * A proving key for the R1CS ppzkSNARK. + */ +template +class r1cs_ppzksnark_proving_key { +public: + knowledge_commitment_vector, G1 > A_query; + knowledge_commitment_vector, G1 > B_query; + knowledge_commitment_vector, G1 > C_query; + G1_vector H_query; + G1_vector K_query; + + r1cs_ppzksnark_proving_key() {}; + r1cs_ppzksnark_proving_key& operator=(const r1cs_ppzksnark_proving_key &other) = default; + r1cs_ppzksnark_proving_key(const r1cs_ppzksnark_proving_key &other) = default; + r1cs_ppzksnark_proving_key(r1cs_ppzksnark_proving_key &&other) = default; + r1cs_ppzksnark_proving_key(knowledge_commitment_vector, G1 > &&A_query, + knowledge_commitment_vector, G1 > &&B_query, + knowledge_commitment_vector, G1 > &&C_query, + G1_vector &&H_query, + G1_vector &&K_query) : + A_query(std::move(A_query)), + B_query(std::move(B_query)), + C_query(std::move(C_query)), + H_query(std::move(H_query)), + K_query(std::move(K_query)) + {}; + + size_t G1_size() const + { + return 2*(A_query.domain_size() + C_query.domain_size()) + B_query.domain_size() + H_query.size() + K_query.size(); + } + + size_t G2_size() const + { + return B_query.domain_size(); + } + + size_t G1_sparse_size() const + { + return 2*(A_query.size() + C_query.size()) + B_query.size() + H_query.size() + K_query.size(); + } + + size_t G2_sparse_size() const + { + return B_query.size(); + } + + size_t size_in_bits() const + { + return A_query.size_in_bits() + B_query.size_in_bits() + C_query.size_in_bits() + libsnark::size_in_bits(H_query) + libsnark::size_in_bits(K_query); + } + + void print_size() const + { + print_indent(); printf("* G1 elements in PK: %zu\n", this->G1_size()); + print_indent(); printf("* Non-zero G1 elements in PK: %zu\n", this->G1_sparse_size()); + print_indent(); printf("* G2 elements in PK: %zu\n", this->G2_size()); + print_indent(); printf("* Non-zero G2 elements in PK: %zu\n", this->G2_sparse_size()); + print_indent(); printf("* PK size in bits: %zu\n", this->size_in_bits()); + } + + bool operator==(const r1cs_ppzksnark_proving_key &other) const; + friend std::ostream& operator<< (std::ostream &out, const r1cs_ppzksnark_proving_key &pk); + friend std::istream& operator>> (std::istream &in, r1cs_ppzksnark_proving_key &pk); +}; + + +/******************************* Verification key ****************************/ + +template +class r1cs_ppzksnark_verification_key; + +template +std::ostream& operator<<(std::ostream &out, const r1cs_ppzksnark_verification_key &vk); + +template +std::istream& operator>>(std::istream &in, r1cs_ppzksnark_verification_key &vk); + +/** + * A verification key for the R1CS ppzkSNARK. + */ +template +class r1cs_ppzksnark_verification_key { +public: + G2 alphaA_g2; + G1 alphaB_g1; + G2 alphaC_g2; + G2 gamma_g2; + G1 gamma_beta_g1; + G2 gamma_beta_g2; + G2 rC_Z_g2; + + accumulation_vector > encoded_IC_query; + + r1cs_ppzksnark_verification_key() = default; + r1cs_ppzksnark_verification_key(const G2 &alphaA_g2, + const G1 &alphaB_g1, + const G2 &alphaC_g2, + const G2 &gamma_g2, + const G1 &gamma_beta_g1, + const G2 &gamma_beta_g2, + const G2 &rC_Z_g2, + const accumulation_vector > &eIC) : + alphaA_g2(alphaA_g2), + alphaB_g1(alphaB_g1), + alphaC_g2(alphaC_g2), + gamma_g2(gamma_g2), + gamma_beta_g1(gamma_beta_g1), + gamma_beta_g2(gamma_beta_g2), + rC_Z_g2(rC_Z_g2), + encoded_IC_query(eIC) + {}; + + size_t G1_size() const + { + return 2 + encoded_IC_query.size(); + } + + size_t G2_size() const + { + return 5; + } + + size_t size_in_bits() const + { + return (2 * G1::size_in_bits() + encoded_IC_query.size_in_bits() + 5 * G2::size_in_bits()); + } + + void print_size() const + { + print_indent(); printf("* G1 elements in VK: %zu\n", this->G1_size()); + print_indent(); printf("* G2 elements in VK: %zu\n", this->G2_size()); + print_indent(); printf("* VK size in bits: %zu\n", this->size_in_bits()); + } + + bool operator==(const r1cs_ppzksnark_verification_key &other) const; + friend std::ostream& operator<< (std::ostream &out, const r1cs_ppzksnark_verification_key &vk); + friend std::istream& operator>> (std::istream &in, r1cs_ppzksnark_verification_key &vk); + + static r1cs_ppzksnark_verification_key dummy_verification_key(const size_t input_size); +}; + + +/************************ Processed verification key *************************/ + +template +class r1cs_ppzksnark_processed_verification_key; + +template +std::ostream& operator<<(std::ostream &out, const r1cs_ppzksnark_processed_verification_key &pvk); + +template +std::istream& operator>>(std::istream &in, r1cs_ppzksnark_processed_verification_key &pvk); + +/** + * A processed verification key for the R1CS ppzkSNARK. + * + * Compared to a (non-processed) verification key, a processed verification key + * contains a small constant amount of additional pre-computed information that + * enables a faster verification time. + */ +template +class r1cs_ppzksnark_processed_verification_key { +public: + G2_precomp pp_G2_one_precomp; + G2_precomp vk_alphaA_g2_precomp; + G1_precomp vk_alphaB_g1_precomp; + G2_precomp vk_alphaC_g2_precomp; + G2_precomp vk_rC_Z_g2_precomp; + G2_precomp vk_gamma_g2_precomp; + G1_precomp vk_gamma_beta_g1_precomp; + G2_precomp vk_gamma_beta_g2_precomp; + + accumulation_vector > encoded_IC_query; + + bool operator==(const r1cs_ppzksnark_processed_verification_key &other) const; + friend std::ostream& operator<< (std::ostream &out, const r1cs_ppzksnark_processed_verification_key &pvk); + friend std::istream& operator>> (std::istream &in, r1cs_ppzksnark_processed_verification_key &pvk); +}; + + +/********************************** Key pair *********************************/ + +/** + * A key pair for the R1CS ppzkSNARK, which consists of a proving key and a verification key. + */ +template +class r1cs_ppzksnark_keypair { +public: + r1cs_ppzksnark_proving_key pk; + r1cs_ppzksnark_verification_key vk; + + r1cs_ppzksnark_keypair() = default; + r1cs_ppzksnark_keypair(const r1cs_ppzksnark_keypair &other) = default; + r1cs_ppzksnark_keypair(r1cs_ppzksnark_proving_key &&pk, + r1cs_ppzksnark_verification_key &&vk) : + pk(std::move(pk)), + vk(std::move(vk)) + {} + + r1cs_ppzksnark_keypair(r1cs_ppzksnark_keypair &&other) = default; +}; + + +/*********************************** Proof ***********************************/ + +template +class r1cs_ppzksnark_proof; + +template +std::ostream& operator<<(std::ostream &out, const r1cs_ppzksnark_proof &proof); + +template +std::istream& operator>>(std::istream &in, r1cs_ppzksnark_proof &proof); + +/** + * A proof for the R1CS ppzkSNARK. + * + * While the proof has a structure, externally one merely opaquely produces, + * seralizes/deserializes, and verifies proofs. We only expose some information + * about the structure for statistics purposes. + */ +template +class r1cs_ppzksnark_proof { +public: + knowledge_commitment, G1 > g_A; + knowledge_commitment, G1 > g_B; + knowledge_commitment, G1 > g_C; + G1 g_H; + G1 g_K; + + r1cs_ppzksnark_proof() + { + // invalid proof with valid curve points + this->g_A.g = G1 ::one(); + this->g_A.h = G1::one(); + this->g_B.g = G2 ::one(); + this->g_B.h = G1::one(); + this->g_C.g = G1 ::one(); + this->g_C.h = G1::one(); + this->g_H = G1::one(); + this->g_K = G1::one(); + } + r1cs_ppzksnark_proof(knowledge_commitment, G1 > &&g_A, + knowledge_commitment, G1 > &&g_B, + knowledge_commitment, G1 > &&g_C, + G1 &&g_H, + G1 &&g_K) : + g_A(std::move(g_A)), + g_B(std::move(g_B)), + g_C(std::move(g_C)), + g_H(std::move(g_H)), + g_K(std::move(g_K)) + {}; + + size_t G1_size() const + { + return 7; + } + + size_t G2_size() const + { + return 1; + } + + size_t size_in_bits() const + { + return G1_size() * G1::size_in_bits() + G2_size() * G2::size_in_bits(); + } + + void print_size() const + { + //print_indent(); printf("* G1 elements in proof: %zu\n", this->G1_size()); + //print_indent(); printf("* G2 elements in proof: %zu\n", this->G2_size()); + //print_indent(); printf("* Proof size in bits: %zu\n", this->size_in_bits()); + } + + bool is_well_formed() const + { + return (g_A.g.is_well_formed() && g_A.h.is_well_formed() && + g_B.g.is_well_formed() && g_B.h.is_well_formed() && + g_C.g.is_well_formed() && g_C.h.is_well_formed() && + g_H.is_well_formed() && + g_K.is_well_formed()); + } + + bool operator==(const r1cs_ppzksnark_proof &other) const; + friend std::ostream& operator<< (std::ostream &out, const r1cs_ppzksnark_proof &proof); + friend std::istream& operator>> (std::istream &in, r1cs_ppzksnark_proof &proof); +}; + + +/***************************** Main algorithms *******************************/ + +/** + * A generator algorithm for the R1CS ppzkSNARK. + * + * Given a R1CS constraint system CS, this algorithm produces proving and verification keys for CS. + */ +template +r1cs_ppzksnark_keypair r1cs_ppzksnark_generator(const r1cs_ppzksnark_constraint_system &cs); + +/** + * A prover algorithm for the R1CS ppzkSNARK. + * + * Given a R1CS primary input X and a R1CS auxiliary input Y, this algorithm + * produces a proof (of knowledge) that attests to the following statement: + * ``there exists Y such that CS(X,Y)=0''. + * Above, CS is the R1CS constraint system that was given as input to the generator algorithm. + */ +template +r1cs_ppzksnark_proof r1cs_ppzksnark_prover(const r1cs_ppzksnark_proving_key &pk, + const r1cs_ppzksnark_primary_input &primary_input, + const r1cs_ppzksnark_auxiliary_input &auxiliary_input, + const r1cs_ppzksnark_constraint_system &cs); + +/* + Below are four variants of verifier algorithm for the R1CS ppzkSNARK. + + These are the four cases that arise from the following two choices: + + (1) The verifier accepts a (non-processed) verification key or, instead, a processed verification key. + In the latter case, we call the algorithm an "online verifier". + + (2) The verifier checks for "weak" input consistency or, instead, "strong" input consistency. + Strong input consistency requires that |primary_input| = CS.num_inputs, whereas + weak input consistency requires that |primary_input| <= CS.num_inputs (and + the primary input is implicitly padded with zeros up to length CS.num_inputs). + */ + +/** + * A verifier algorithm for the R1CS ppzkSNARK that: + * (1) accepts a non-processed verification key, and + * (2) has weak input consistency. + */ +template +bool r1cs_ppzksnark_verifier_weak_IC(const r1cs_ppzksnark_verification_key &vk, + const r1cs_ppzksnark_primary_input &primary_input, + const r1cs_ppzksnark_proof &proof); + +/** + * A verifier algorithm for the R1CS ppzkSNARK that: + * (1) accepts a non-processed verification key, and + * (2) has strong input consistency. + */ +template +bool r1cs_ppzksnark_verifier_strong_IC(const r1cs_ppzksnark_verification_key &vk, + const r1cs_ppzksnark_primary_input &primary_input, + const r1cs_ppzksnark_proof &proof); + +/** + * Convert a (non-processed) verification key into a processed verification key. + */ +template +r1cs_ppzksnark_processed_verification_key r1cs_ppzksnark_verifier_process_vk(const r1cs_ppzksnark_verification_key &vk); + +/** + * A verifier algorithm for the R1CS ppzkSNARK that: + * (1) accepts a processed verification key, and + * (2) has weak input consistency. + */ +template +bool r1cs_ppzksnark_online_verifier_weak_IC(const r1cs_ppzksnark_processed_verification_key &pvk, + const r1cs_ppzksnark_primary_input &input, + const r1cs_ppzksnark_proof &proof); + +/** + * A verifier algorithm for the R1CS ppzkSNARK that: + * (1) accepts a processed verification key, and + * (2) has strong input consistency. + */ +template +bool r1cs_ppzksnark_online_verifier_strong_IC(const r1cs_ppzksnark_processed_verification_key &pvk, + const r1cs_ppzksnark_primary_input &primary_input, + const r1cs_ppzksnark_proof &proof); + +/****************************** Miscellaneous ********************************/ + +/** + * For debugging purposes (of r1cs_ppzksnark_r1cs_ppzksnark_verifier_gadget): + * + * A verifier algorithm for the R1CS ppzkSNARK that: + * (1) accepts a non-processed verification key, + * (2) has weak input consistency, and + * (3) uses affine coordinates for elliptic-curve computations. + */ +template +bool r1cs_ppzksnark_affine_verifier_weak_IC(const r1cs_ppzksnark_verification_key &vk, + const r1cs_ppzksnark_primary_input &primary_input, + const r1cs_ppzksnark_proof &proof); + + +} // libsnark + +#include "zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.tcc" + +#endif // R1CS_PPZKSNARK_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.tcc b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.tcc new file mode 100644 index 0000000..008aa44 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.tcc @@ -0,0 +1,789 @@ +/** @file +***************************************************************************** + +Implementation of interfaces for a ppzkSNARK for R1CS. + +See r1cs_ppzksnark.hpp . + +***************************************************************************** +* @author This file is part of libsnark, developed by SCIPR Lab +* and contributors (see AUTHORS). +* @copyright MIT license (see LICENSE file) +*****************************************************************************/ + +#ifndef R1CS_PPZKSNARK_TCC_ +#define R1CS_PPZKSNARK_TCC_ + +#include +#include +#include +#include +#include + +#include "common/profiling.hpp" +#include "common/utils.hpp" +#include "algebra/scalar_multiplication/multiexp.hpp" +#include "algebra/scalar_multiplication/kc_multiexp.hpp" +#include "reductions/r1cs_to_qap/r1cs_to_qap.hpp" + +namespace libsnark { + +template +bool r1cs_ppzksnark_proving_key::operator==(const r1cs_ppzksnark_proving_key &other) const +{ + return (this->A_query == other.A_query && + this->B_query == other.B_query && + this->C_query == other.C_query && + this->H_query == other.H_query && + this->K_query == other.K_query); +} + +template +std::ostream& operator<<(std::ostream &out, const r1cs_ppzksnark_proving_key &pk) +{ + out << pk.A_query; + out << pk.B_query; + out << pk.C_query; + out << pk.H_query; + out << pk.K_query; + + return out; +} + +template +std::istream& operator>>(std::istream &in, r1cs_ppzksnark_proving_key &pk) +{ + in >> pk.A_query; + in >> pk.B_query; + in >> pk.C_query; + in >> pk.H_query; + in >> pk.K_query; + + return in; +} + +template +bool r1cs_ppzksnark_verification_key::operator==(const r1cs_ppzksnark_verification_key &other) const +{ + return (this->alphaA_g2 == other.alphaA_g2 && + this->alphaB_g1 == other.alphaB_g1 && + this->alphaC_g2 == other.alphaC_g2 && + this->gamma_g2 == other.gamma_g2 && + this->gamma_beta_g1 == other.gamma_beta_g1 && + this->gamma_beta_g2 == other.gamma_beta_g2 && + this->rC_Z_g2 == other.rC_Z_g2 && + this->encoded_IC_query == other.encoded_IC_query); +} + +template +std::ostream& operator<<(std::ostream &out, const r1cs_ppzksnark_verification_key &vk) +{ + out << vk.alphaA_g2 << OUTPUT_NEWLINE; + out << vk.alphaB_g1 << OUTPUT_NEWLINE; + out << vk.alphaC_g2 << OUTPUT_NEWLINE; + out << vk.gamma_g2 << OUTPUT_NEWLINE; + out << vk.gamma_beta_g1 << OUTPUT_NEWLINE; + out << vk.gamma_beta_g2 << OUTPUT_NEWLINE; + out << vk.rC_Z_g2 << OUTPUT_NEWLINE; + out << vk.encoded_IC_query << OUTPUT_NEWLINE; + + return out; +} + +template +std::istream& operator>>(std::istream &in, r1cs_ppzksnark_verification_key &vk) +{ + in >> vk.alphaA_g2; + consume_OUTPUT_NEWLINE(in); + in >> vk.alphaB_g1; + consume_OUTPUT_NEWLINE(in); + in >> vk.alphaC_g2; + consume_OUTPUT_NEWLINE(in); + in >> vk.gamma_g2; + consume_OUTPUT_NEWLINE(in); + in >> vk.gamma_beta_g1; + consume_OUTPUT_NEWLINE(in); + in >> vk.gamma_beta_g2; + consume_OUTPUT_NEWLINE(in); + in >> vk.rC_Z_g2; + consume_OUTPUT_NEWLINE(in); + in >> vk.encoded_IC_query; + consume_OUTPUT_NEWLINE(in); + + return in; +} + +template +bool r1cs_ppzksnark_processed_verification_key::operator==(const r1cs_ppzksnark_processed_verification_key &other) const +{ + return (this->pp_G2_one_precomp == other.pp_G2_one_precomp && + this->vk_alphaA_g2_precomp == other.vk_alphaA_g2_precomp && + this->vk_alphaB_g1_precomp == other.vk_alphaB_g1_precomp && + this->vk_alphaC_g2_precomp == other.vk_alphaC_g2_precomp && + this->vk_rC_Z_g2_precomp == other.vk_rC_Z_g2_precomp && + this->vk_gamma_g2_precomp == other.vk_gamma_g2_precomp && + this->vk_gamma_beta_g1_precomp == other.vk_gamma_beta_g1_precomp && + this->vk_gamma_beta_g2_precomp == other.vk_gamma_beta_g2_precomp && + this->encoded_IC_query == other.encoded_IC_query); +} + +template +std::ostream& operator<<(std::ostream &out, const r1cs_ppzksnark_processed_verification_key &pvk) +{ + out << pvk.pp_G2_one_precomp << OUTPUT_NEWLINE; + out << pvk.vk_alphaA_g2_precomp << OUTPUT_NEWLINE; + out << pvk.vk_alphaB_g1_precomp << OUTPUT_NEWLINE; + out << pvk.vk_alphaC_g2_precomp << OUTPUT_NEWLINE; + out << pvk.vk_rC_Z_g2_precomp << OUTPUT_NEWLINE; + out << pvk.vk_gamma_g2_precomp << OUTPUT_NEWLINE; + out << pvk.vk_gamma_beta_g1_precomp << OUTPUT_NEWLINE; + out << pvk.vk_gamma_beta_g2_precomp << OUTPUT_NEWLINE; + out << pvk.encoded_IC_query << OUTPUT_NEWLINE; + + return out; +} + +template +std::istream& operator>>(std::istream &in, r1cs_ppzksnark_processed_verification_key &pvk) +{ + in >> pvk.pp_G2_one_precomp; + consume_OUTPUT_NEWLINE(in); + in >> pvk.vk_alphaA_g2_precomp; + consume_OUTPUT_NEWLINE(in); + in >> pvk.vk_alphaB_g1_precomp; + consume_OUTPUT_NEWLINE(in); + in >> pvk.vk_alphaC_g2_precomp; + consume_OUTPUT_NEWLINE(in); + in >> pvk.vk_rC_Z_g2_precomp; + consume_OUTPUT_NEWLINE(in); + in >> pvk.vk_gamma_g2_precomp; + consume_OUTPUT_NEWLINE(in); + in >> pvk.vk_gamma_beta_g1_precomp; + consume_OUTPUT_NEWLINE(in); + in >> pvk.vk_gamma_beta_g2_precomp; + consume_OUTPUT_NEWLINE(in); + in >> pvk.encoded_IC_query; + consume_OUTPUT_NEWLINE(in); + + return in; +} + +template +bool r1cs_ppzksnark_proof::operator==(const r1cs_ppzksnark_proof &other) const +{ + return (this->g_A == other.g_A && + this->g_B == other.g_B && + this->g_C == other.g_C && + this->g_H == other.g_H && + this->g_K == other.g_K); +} + +template +std::ostream& operator<<(std::ostream &out, const r1cs_ppzksnark_proof &proof) +{ + out << proof.g_A << OUTPUT_NEWLINE; + out << proof.g_B << OUTPUT_NEWLINE; + out << proof.g_C << OUTPUT_NEWLINE; + out << proof.g_H << OUTPUT_NEWLINE; + out << proof.g_K << OUTPUT_NEWLINE; + + return out; +} + +template +std::istream& operator>>(std::istream &in, r1cs_ppzksnark_proof &proof) +{ + in >> proof.g_A; + consume_OUTPUT_NEWLINE(in); + in >> proof.g_B; + consume_OUTPUT_NEWLINE(in); + in >> proof.g_C; + consume_OUTPUT_NEWLINE(in); + in >> proof.g_H; + consume_OUTPUT_NEWLINE(in); + in >> proof.g_K; + consume_OUTPUT_NEWLINE(in); + + return in; +} + +template +r1cs_ppzksnark_verification_key r1cs_ppzksnark_verification_key::dummy_verification_key(const size_t input_size) +{ + r1cs_ppzksnark_verification_key result; + result.alphaA_g2 = Fr::random_element() * G2::one(); + result.alphaB_g1 = Fr::random_element() * G1::one(); + result.alphaC_g2 = Fr::random_element() * G2::one(); + result.gamma_g2 = Fr::random_element() * G2::one(); + result.gamma_beta_g1 = Fr::random_element() * G1::one(); + result.gamma_beta_g2 = Fr::random_element() * G2::one(); + result.rC_Z_g2 = Fr::random_element() * G2::one(); + + G1 base = Fr::random_element() * G1::one(); + G1_vector v; + for (size_t i = 0; i < input_size; ++i) + { + v.emplace_back(Fr::random_element() * G1::one()); + } + + result.encoded_IC_query = accumulation_vector >(std::move(base), std::move(v)); + + return result; +} + +template +r1cs_ppzksnark_keypair r1cs_ppzksnark_generator(const r1cs_ppzksnark_constraint_system &cs) +{ + enter_block("Call to r1cs_ppzksnark_generator"); + + /* make the B_query "lighter" if possible */ + r1cs_ppzksnark_constraint_system cs_copy(cs); + cs_copy.swap_AB_if_beneficial(); + + /* draw random element at which the QAP is evaluated */ + const Fr t = Fr::random_element(); + + qap_instance_evaluation > qap_inst = r1cs_to_qap_instance_map_with_evaluation(cs_copy, t); + + print_indent(); printf("* QAP number of variables: %zu\n", qap_inst.num_variables()); + print_indent(); printf("* QAP pre degree: %zu\n", cs_copy.constraints.size()); + print_indent(); printf("* QAP degree: %zu\n", qap_inst.degree()); + print_indent(); printf("* QAP number of input variables: %zu\n", qap_inst.num_inputs()); + + enter_block("Compute query densities"); + size_t non_zero_At = 0, non_zero_Bt = 0, non_zero_Ct = 0, non_zero_Ht = 0; + for (size_t i = 0; i < qap_inst.num_variables()+1; ++i) + { + if (!qap_inst.At[i].is_zero()) + { + ++non_zero_At; + } + if (!qap_inst.Bt[i].is_zero()) + { + ++non_zero_Bt; + } + if (!qap_inst.Ct[i].is_zero()) + { + ++non_zero_Ct; + } + } + for (size_t i = 0; i < qap_inst.degree()+1; ++i) + { + if (!qap_inst.Ht[i].is_zero()) + { + ++non_zero_Ht; + } + } + leave_block("Compute query densities"); + + Fr_vector At = std::move(qap_inst.At); // qap_inst.At is now in unspecified state, but we do not use it later + Fr_vector Bt = std::move(qap_inst.Bt); // qap_inst.Bt is now in unspecified state, but we do not use it later + Fr_vector Ct = std::move(qap_inst.Ct); // qap_inst.Ct is now in unspecified state, but we do not use it later + Fr_vector Ht = std::move(qap_inst.Ht); // qap_inst.Ht is now in unspecified state, but we do not use it later + + /* append Zt to At,Bt,Ct with */ + At.emplace_back(qap_inst.Zt); + Bt.emplace_back(qap_inst.Zt); + Ct.emplace_back(qap_inst.Zt); + + const Fr alphaA = Fr::random_element(), + alphaB = Fr::random_element(), + alphaC = Fr::random_element(), + rA = Fr::random_element(), + rB = Fr::random_element(), + beta = Fr::random_element(), + gamma = Fr::random_element(); + const Fr rC = rA * rB; + + // consrtuct the same-coefficient-check query (must happen before zeroing out the prefix of At) + Fr_vector Kt; + Kt.reserve(qap_inst.num_variables()+4); + for (size_t i = 0; i < qap_inst.num_variables()+1; ++i) + { + Kt.emplace_back( beta * (rA * At[i] + rB * Bt[i] + rC * Ct[i] ) ); + } + Kt.emplace_back(beta * rA * qap_inst.Zt); + Kt.emplace_back(beta * rB * qap_inst.Zt); + Kt.emplace_back(beta * rC * qap_inst.Zt); + + /* zero out prefix of At and stick it into IC coefficients */ + Fr_vector IC_coefficients; + IC_coefficients.reserve(qap_inst.num_inputs() + 1); + for (size_t i = 0; i < qap_inst.num_inputs() + 1; ++i) + { + IC_coefficients.emplace_back(At[i]); + assert(!IC_coefficients[i].is_zero()); + At[i] = Fr::zero(); + } + + const size_t g1_exp_count = 2*(non_zero_At - qap_inst.num_inputs() + non_zero_Ct) + non_zero_Bt + non_zero_Ht + Kt.size(); + const size_t g2_exp_count = non_zero_Bt; + + size_t g1_window = get_exp_window_size >(g1_exp_count); + size_t g2_window = get_exp_window_size >(g2_exp_count); + print_indent(); printf("* G1 window: %zu\n", g1_window); + print_indent(); printf("* G2 window: %zu\n", g2_window); + +#ifdef MULTICORE + const size_t chunks = omp_get_max_threads(); // to override, set OMP_NUM_THREADS env var or call omp_set_num_threads() +#else + const size_t chunks = 1; +#endif + + enter_block("Generating G1 multiexp table"); + window_table > g1_table = get_window_table(Fr::size_in_bits(), g1_window, G1::one()); + leave_block("Generating G1 multiexp table"); + + enter_block("Generating G2 multiexp table"); + window_table > g2_table = get_window_table(Fr::size_in_bits(), g2_window, G2::one()); + leave_block("Generating G2 multiexp table"); + + enter_block("Generate R1CS proving key"); + + enter_block("Generate knowledge commitments"); + enter_block("Compute the A-query", false); + knowledge_commitment_vector, G1 > A_query = kc_batch_exp(Fr::size_in_bits(), g1_window, g1_window, g1_table, g1_table, rA, rA*alphaA, At, chunks); + leave_block("Compute the A-query", false); + + enter_block("Compute the B-query", false); + knowledge_commitment_vector, G1 > B_query = kc_batch_exp(Fr::size_in_bits(), g2_window, g1_window, g2_table, g1_table, rB, rB*alphaB, Bt, chunks); + leave_block("Compute the B-query", false); + + enter_block("Compute the C-query", false); + knowledge_commitment_vector, G1 > C_query = kc_batch_exp(Fr::size_in_bits(), g1_window, g1_window, g1_table, g1_table, rC, rC*alphaC, Ct, chunks); + leave_block("Compute the C-query", false); + + enter_block("Compute the H-query", false); + G1_vector H_query = batch_exp(Fr::size_in_bits(), g1_window, g1_table, Ht); + leave_block("Compute the H-query", false); + + enter_block("Compute the K-query", false); + G1_vector K_query = batch_exp(Fr::size_in_bits(), g1_window, g1_table, Kt); +#ifdef USE_MIXED_ADDITION + batch_to_special >(K_query); +#endif + leave_block("Compute the K-query", false); + + leave_block("Generate knowledge commitments"); + + leave_block("Generate R1CS proving key"); + + enter_block("Generate R1CS verification key"); + G2 alphaA_g2 = alphaA * G2::one(); + G1 alphaB_g1 = alphaB * G1::one(); + G2 alphaC_g2 = alphaC * G2::one(); + G2 gamma_g2 = gamma * G2::one(); + G1 gamma_beta_g1 = (gamma * beta) * G1::one(); + G2 gamma_beta_g2 = (gamma * beta) * G2::one(); + G2 rC_Z_g2 = (rC * qap_inst.Zt) * G2::one(); + + enter_block("Encode IC query for R1CS verification key"); + G1 encoded_IC_base = (rA * IC_coefficients[0]) * G1::one(); + Fr_vector multiplied_IC_coefficients; + multiplied_IC_coefficients.reserve(qap_inst.num_inputs()); + for (size_t i = 1; i < qap_inst.num_inputs() + 1; ++i) + { + multiplied_IC_coefficients.emplace_back(rA * IC_coefficients[i]); + } + G1_vector encoded_IC_values = batch_exp(Fr::size_in_bits(), g1_window, g1_table, multiplied_IC_coefficients); + + leave_block("Encode IC query for R1CS verification key"); + leave_block("Generate R1CS verification key"); + + leave_block("Call to r1cs_ppzksnark_generator"); + + accumulation_vector > encoded_IC_query(std::move(encoded_IC_base), std::move(encoded_IC_values)); + + r1cs_ppzksnark_verification_key vk = r1cs_ppzksnark_verification_key(alphaA_g2, + alphaB_g1, + alphaC_g2, + gamma_g2, + gamma_beta_g1, + gamma_beta_g2, + rC_Z_g2, + encoded_IC_query); + r1cs_ppzksnark_proving_key pk = r1cs_ppzksnark_proving_key(std::move(A_query), + std::move(B_query), + std::move(C_query), + std::move(H_query), + std::move(K_query)); + + pk.print_size(); + vk.print_size(); + + return r1cs_ppzksnark_keypair(std::move(pk), std::move(vk)); +} + +template +r1cs_ppzksnark_proof r1cs_ppzksnark_prover(const r1cs_ppzksnark_proving_key &pk, + const r1cs_ppzksnark_primary_input &primary_input, + const r1cs_ppzksnark_auxiliary_input &auxiliary_input, + const r1cs_ppzksnark_constraint_system &cs) +{ + enter_block("Call to r1cs_ppzksnark_prover"); + +#ifdef DEBUG + assert(pk.constraint_system.is_satisfied(primary_input, auxiliary_input)); +#endif + + const Fr d1 = Fr::random_element(), + d2 = Fr::random_element(), + d3 = Fr::random_element(); + + enter_block("Compute the polynomial H"); + const qap_witness > qap_wit = r1cs_to_qap_witness_map(cs, primary_input, auxiliary_input, d1, d2, d3); + leave_block("Compute the polynomial H"); + +#ifdef DEBUG + const Fr t = Fr::random_element(); + qap_instance_evaluation > qap_inst = r1cs_to_qap_instance_map_with_evaluation(pk.constraint_system, t); + assert(qap_inst.is_satisfied(qap_wit)); +#endif + + knowledge_commitment, G1 > g_A = pk.A_query[0] + qap_wit.d1*pk.A_query[qap_wit.num_variables()+1]; + knowledge_commitment, G1 > g_B = pk.B_query[0] + qap_wit.d2*pk.B_query[qap_wit.num_variables()+1]; + knowledge_commitment, G1 > g_C = pk.C_query[0] + qap_wit.d3*pk.C_query[qap_wit.num_variables()+1]; + + G1 g_H = G1::zero(); + G1 g_K = (pk.K_query[0] + + qap_wit.d1*pk.K_query[qap_wit.num_variables()+1] + + qap_wit.d2*pk.K_query[qap_wit.num_variables()+2] + + qap_wit.d3*pk.K_query[qap_wit.num_variables()+3]); + +#ifdef DEBUG + for (size_t i = 0; i < qap_wit.num_inputs() + 1; ++i) + { + assert(pk.A_query[i].g == G1::zero()); + } + assert(pk.A_query.domain_size() == qap_wit.num_variables()+2); + assert(pk.B_query.domain_size() == qap_wit.num_variables()+2); + assert(pk.C_query.domain_size() == qap_wit.num_variables()+2); + assert(pk.H_query.size() == qap_wit.degree()+1); + assert(pk.K_query.size() == qap_wit.num_variables()+4); +#endif + +#ifdef MULTICORE + const size_t chunks = omp_get_max_threads(); // to override, set OMP_NUM_THREADS env var or call omp_set_num_threads() +#else + const size_t chunks = 1; +#endif + + enter_block("Compute the proof"); + + enter_block("Compute answer to A-query", false); + g_A = g_A + kc_multi_exp_with_mixed_addition, G1, Fr >(pk.A_query, + 1, 1+qap_wit.num_variables(), + qap_wit.coefficients_for_ABCs.begin(), qap_wit.coefficients_for_ABCs.begin()+qap_wit.num_variables(), + chunks, true); + leave_block("Compute answer to A-query", false); + + enter_block("Compute answer to B-query", false); + g_B = g_B + kc_multi_exp_with_mixed_addition, G1, Fr >(pk.B_query, + 1, 1+qap_wit.num_variables(), + qap_wit.coefficients_for_ABCs.begin(), qap_wit.coefficients_for_ABCs.begin()+qap_wit.num_variables(), + chunks, true); + leave_block("Compute answer to B-query", false); + + enter_block("Compute answer to C-query", false); + g_C = g_C + kc_multi_exp_with_mixed_addition, G1, Fr >(pk.C_query, + 1, 1+qap_wit.num_variables(), + qap_wit.coefficients_for_ABCs.begin(), qap_wit.coefficients_for_ABCs.begin()+qap_wit.num_variables(), + chunks, true); + leave_block("Compute answer to C-query", false); + + enter_block("Compute answer to H-query", false); + g_H = g_H + multi_exp, Fr >(pk.H_query.begin(), pk.H_query.begin()+qap_wit.degree()+1, + qap_wit.coefficients_for_H.begin(), qap_wit.coefficients_for_H.begin()+qap_wit.degree()+1, + chunks, true); + leave_block("Compute answer to H-query", false); + + enter_block("Compute answer to K-query", false); + g_K = g_K + multi_exp_with_mixed_addition, Fr >(pk.K_query.begin()+1, pk.K_query.begin()+1+qap_wit.num_variables(), + qap_wit.coefficients_for_ABCs.begin(), qap_wit.coefficients_for_ABCs.begin()+qap_wit.num_variables(), + chunks, true); + leave_block("Compute answer to K-query", false); + + leave_block("Compute the proof"); + + leave_block("Call to r1cs_ppzksnark_prover"); + + r1cs_ppzksnark_proof proof = r1cs_ppzksnark_proof(std::move(g_A), std::move(g_B), std::move(g_C), std::move(g_H), std::move(g_K)); + proof.print_size(); + + return proof; +} + +template +r1cs_ppzksnark_processed_verification_key r1cs_ppzksnark_verifier_process_vk(const r1cs_ppzksnark_verification_key &vk) +{ + enter_block("Call to r1cs_ppzksnark_verifier_process_vk"); + + r1cs_ppzksnark_processed_verification_key pvk; + pvk.pp_G2_one_precomp = ppT::precompute_G2(G2::one()); + pvk.vk_alphaA_g2_precomp = ppT::precompute_G2(vk.alphaA_g2); + pvk.vk_alphaB_g1_precomp = ppT::precompute_G1(vk.alphaB_g1); + pvk.vk_alphaC_g2_precomp = ppT::precompute_G2(vk.alphaC_g2); + pvk.vk_rC_Z_g2_precomp = ppT::precompute_G2(vk.rC_Z_g2); + pvk.vk_gamma_g2_precomp = ppT::precompute_G2(vk.gamma_g2); + pvk.vk_gamma_beta_g1_precomp = ppT::precompute_G1(vk.gamma_beta_g1); + pvk.vk_gamma_beta_g2_precomp = ppT::precompute_G2(vk.gamma_beta_g2); + + pvk.encoded_IC_query = vk.encoded_IC_query; + + leave_block("Call to r1cs_ppzksnark_verifier_process_vk"); + + return pvk; +} + +template +bool r1cs_ppzksnark_online_verifier_weak_IC(const r1cs_ppzksnark_processed_verification_key &pvk, + const r1cs_ppzksnark_primary_input &primary_input, + const r1cs_ppzksnark_proof &proof) +{ + enter_block("Call to r1cs_ppzksnark_online_verifier_weak_IC"); + assert(pvk.encoded_IC_query.domain_size() >= primary_input.size()); + + enter_block("Compute input-dependent part of A"); + const accumulation_vector > accumulated_IC = pvk.encoded_IC_query.template accumulate_chunk >(primary_input.begin(), primary_input.end(), 0); + const G1 &acc = accumulated_IC.first; + leave_block("Compute input-dependent part of A"); + + bool result = true; + + enter_block("Check if the proof is well-formed"); + if (!proof.is_well_formed()) + { + if (!inhibit_profiling_info) + { + print_indent(); printf("At least one of the proof elements does not lie on the curve.\n"); + } + result = false; + } + leave_block("Check if the proof is well-formed"); + + enter_block("Online pairing computations"); + enter_block("Check knowledge commitment for A is valid"); + G1_precomp proof_g_A_g_precomp = ppT::precompute_G1(proof.g_A.g); + G1_precomp proof_g_A_h_precomp = ppT::precompute_G1(proof.g_A.h); + Fqk kc_A_1 = ppT::miller_loop(proof_g_A_g_precomp, pvk.vk_alphaA_g2_precomp); + Fqk kc_A_2 = ppT::miller_loop(proof_g_A_h_precomp, pvk.pp_G2_one_precomp); + GT kc_A = ppT::final_exponentiation(kc_A_1 * kc_A_2.unitary_inverse()); + if (kc_A != GT::one()) + { + if (!inhibit_profiling_info) + { + print_indent(); printf("Knowledge commitment for A query incorrect.\n"); + } + result = false; + } + leave_block("Check knowledge commitment for A is valid"); + + enter_block("Check knowledge commitment for B is valid"); + G2_precomp proof_g_B_g_precomp = ppT::precompute_G2(proof.g_B.g); + G1_precomp proof_g_B_h_precomp = ppT::precompute_G1(proof.g_B.h); + Fqk kc_B_1 = ppT::miller_loop(pvk.vk_alphaB_g1_precomp, proof_g_B_g_precomp); + Fqk kc_B_2 = ppT::miller_loop(proof_g_B_h_precomp, pvk.pp_G2_one_precomp); + GT kc_B = ppT::final_exponentiation(kc_B_1 * kc_B_2.unitary_inverse()); + if (kc_B != GT::one()) + { + if (!inhibit_profiling_info) + { + print_indent(); printf("Knowledge commitment for B query incorrect.\n"); + } + result = false; + } + leave_block("Check knowledge commitment for B is valid"); + + enter_block("Check knowledge commitment for C is valid"); + G1_precomp proof_g_C_g_precomp = ppT::precompute_G1(proof.g_C.g); + G1_precomp proof_g_C_h_precomp = ppT::precompute_G1(proof.g_C.h); + Fqk kc_C_1 = ppT::miller_loop(proof_g_C_g_precomp, pvk.vk_alphaC_g2_precomp); + Fqk kc_C_2 = ppT::miller_loop(proof_g_C_h_precomp, pvk.pp_G2_one_precomp); + GT kc_C = ppT::final_exponentiation(kc_C_1 * kc_C_2.unitary_inverse()); + if (kc_C != GT::one()) + { + if (!inhibit_profiling_info) + { + print_indent(); printf("Knowledge commitment for C query incorrect.\n"); + } + result = false; + } + leave_block("Check knowledge commitment for C is valid"); + + enter_block("Check QAP divisibility"); + // check that g^((A+acc)*B)=g^(H*\Prod(t-\sigma)+C) + // equivalently, via pairings, that e(g^(A+acc), g^B) = e(g^H, g^Z) + e(g^C, g^1) + G1_precomp proof_g_A_g_acc_precomp = ppT::precompute_G1(proof.g_A.g + acc); + G1_precomp proof_g_H_precomp = ppT::precompute_G1(proof.g_H); + Fqk QAP_1 = ppT::miller_loop(proof_g_A_g_acc_precomp, proof_g_B_g_precomp); + Fqk QAP_23 = ppT::double_miller_loop(proof_g_H_precomp, pvk.vk_rC_Z_g2_precomp, proof_g_C_g_precomp, pvk.pp_G2_one_precomp); + GT QAP = ppT::final_exponentiation(QAP_1 * QAP_23.unitary_inverse()); + if (QAP != GT::one()) + { + if (!inhibit_profiling_info) + { + print_indent(); printf("QAP divisibility check failed.\n"); + } + result = false; + } + leave_block("Check QAP divisibility"); + + enter_block("Check same coefficients were used"); + G1_precomp proof_g_K_precomp = ppT::precompute_G1(proof.g_K); + G1_precomp proof_g_A_g_acc_C_precomp = ppT::precompute_G1((proof.g_A.g + acc) + proof.g_C.g); + Fqk K_1 = ppT::miller_loop(proof_g_K_precomp, pvk.vk_gamma_g2_precomp); + Fqk K_23 = ppT::double_miller_loop(proof_g_A_g_acc_C_precomp, pvk.vk_gamma_beta_g2_precomp, pvk.vk_gamma_beta_g1_precomp, proof_g_B_g_precomp); + GT K = ppT::final_exponentiation(K_1 * K_23.unitary_inverse()); + if (K != GT::one()) + { + if (!inhibit_profiling_info) + { + print_indent(); printf("Same-coefficient check failed.\n"); + } + result = false; + } + leave_block("Check same coefficients were used"); + leave_block("Online pairing computations"); + leave_block("Call to r1cs_ppzksnark_online_verifier_weak_IC"); + + return result; +} + +template +bool r1cs_ppzksnark_verifier_weak_IC(const r1cs_ppzksnark_verification_key &vk, + const r1cs_ppzksnark_primary_input &primary_input, + const r1cs_ppzksnark_proof &proof) +{ + enter_block("Call to r1cs_ppzksnark_verifier_weak_IC"); + r1cs_ppzksnark_processed_verification_key pvk = r1cs_ppzksnark_verifier_process_vk(vk); + bool result = r1cs_ppzksnark_online_verifier_weak_IC(pvk, primary_input, proof); + leave_block("Call to r1cs_ppzksnark_verifier_weak_IC"); + return result; +} + +template +bool r1cs_ppzksnark_online_verifier_strong_IC(const r1cs_ppzksnark_processed_verification_key &pvk, + const r1cs_ppzksnark_primary_input &primary_input, + const r1cs_ppzksnark_proof &proof) +{ + bool result = true; + enter_block("Call to r1cs_ppzksnark_online_verifier_strong_IC"); + + if (pvk.encoded_IC_query.domain_size() != primary_input.size()) + { + print_indent(); printf("Input length differs from expected (got %zu, expected %zu).\n", primary_input.size(), pvk.encoded_IC_query.domain_size()); + result = false; + } + else + { + result = r1cs_ppzksnark_online_verifier_weak_IC(pvk, primary_input, proof); + } + + leave_block("Call to r1cs_ppzksnark_online_verifier_strong_IC"); + return result; +} + +template +bool r1cs_ppzksnark_verifier_strong_IC(const r1cs_ppzksnark_verification_key &vk, + const r1cs_ppzksnark_primary_input &primary_input, + const r1cs_ppzksnark_proof &proof) +{ + enter_block("Call to r1cs_ppzksnark_verifier_strong_IC"); + r1cs_ppzksnark_processed_verification_key pvk = r1cs_ppzksnark_verifier_process_vk(vk); + bool result = r1cs_ppzksnark_online_verifier_strong_IC(pvk, primary_input, proof); + leave_block("Call to r1cs_ppzksnark_verifier_strong_IC"); + return result; +} + +template +bool r1cs_ppzksnark_affine_verifier_weak_IC(const r1cs_ppzksnark_verification_key &vk, + const r1cs_ppzksnark_primary_input &primary_input, + const r1cs_ppzksnark_proof &proof) +{ + enter_block("Call to r1cs_ppzksnark_affine_verifier_weak_IC"); + assert(vk.encoded_IC_query.domain_size() >= primary_input.size()); + + affine_ate_G2_precomp pvk_pp_G2_one_precomp = ppT::affine_ate_precompute_G2(G2::one()); + affine_ate_G2_precomp pvk_vk_alphaA_g2_precomp = ppT::affine_ate_precompute_G2(vk.alphaA_g2); + affine_ate_G1_precomp pvk_vk_alphaB_g1_precomp = ppT::affine_ate_precompute_G1(vk.alphaB_g1); + affine_ate_G2_precomp pvk_vk_alphaC_g2_precomp = ppT::affine_ate_precompute_G2(vk.alphaC_g2); + affine_ate_G2_precomp pvk_vk_rC_Z_g2_precomp = ppT::affine_ate_precompute_G2(vk.rC_Z_g2); + affine_ate_G2_precomp pvk_vk_gamma_g2_precomp = ppT::affine_ate_precompute_G2(vk.gamma_g2); + affine_ate_G1_precomp pvk_vk_gamma_beta_g1_precomp = ppT::affine_ate_precompute_G1(vk.gamma_beta_g1); + affine_ate_G2_precomp pvk_vk_gamma_beta_g2_precomp = ppT::affine_ate_precompute_G2(vk.gamma_beta_g2); + + enter_block("Compute input-dependent part of A"); + const accumulation_vector > accumulated_IC = vk.encoded_IC_query.template accumulate_chunk >(primary_input.begin(), primary_input.end(), 0); + assert(accumulated_IC.is_fully_accumulated()); + const G1 &acc = accumulated_IC.first; + leave_block("Compute input-dependent part of A"); + + bool result = true; + enter_block("Check knowledge commitment for A is valid"); + affine_ate_G1_precomp proof_g_A_g_precomp = ppT::affine_ate_precompute_G1(proof.g_A.g); + affine_ate_G1_precomp proof_g_A_h_precomp = ppT::affine_ate_precompute_G1(proof.g_A.h); + Fqk kc_A_miller = ppT::affine_ate_e_over_e_miller_loop(proof_g_A_g_precomp, pvk_vk_alphaA_g2_precomp, proof_g_A_h_precomp, pvk_pp_G2_one_precomp); + GT kc_A = ppT::final_exponentiation(kc_A_miller); + + if (kc_A != GT::one()) + { + print_indent(); printf("Knowledge commitment for A query incorrect.\n"); + result = false; + } + leave_block("Check knowledge commitment for A is valid"); + + enter_block("Check knowledge commitment for B is valid"); + affine_ate_G2_precomp proof_g_B_g_precomp = ppT::affine_ate_precompute_G2(proof.g_B.g); + affine_ate_G1_precomp proof_g_B_h_precomp = ppT::affine_ate_precompute_G1(proof.g_B.h); + Fqk kc_B_miller = ppT::affine_ate_e_over_e_miller_loop(pvk_vk_alphaB_g1_precomp, proof_g_B_g_precomp, proof_g_B_h_precomp, pvk_pp_G2_one_precomp); + GT kc_B = ppT::final_exponentiation(kc_B_miller); + if (kc_B != GT::one()) + { + print_indent(); printf("Knowledge commitment for B query incorrect.\n"); + result = false; + } + leave_block("Check knowledge commitment for B is valid"); + + enter_block("Check knowledge commitment for C is valid"); + affine_ate_G1_precomp proof_g_C_g_precomp = ppT::affine_ate_precompute_G1(proof.g_C.g); + affine_ate_G1_precomp proof_g_C_h_precomp = ppT::affine_ate_precompute_G1(proof.g_C.h); + Fqk kc_C_miller = ppT::affine_ate_e_over_e_miller_loop(proof_g_C_g_precomp, pvk_vk_alphaC_g2_precomp, proof_g_C_h_precomp, pvk_pp_G2_one_precomp); + GT kc_C = ppT::final_exponentiation(kc_C_miller); + if (kc_C != GT::one()) + { + print_indent(); printf("Knowledge commitment for C query incorrect.\n"); + result = false; + } + leave_block("Check knowledge commitment for C is valid"); + + enter_block("Check QAP divisibility"); + affine_ate_G1_precomp proof_g_A_g_acc_precomp = ppT::affine_ate_precompute_G1(proof.g_A.g + acc); + affine_ate_G1_precomp proof_g_H_precomp = ppT::affine_ate_precompute_G1(proof.g_H); + Fqk QAP_miller = ppT::affine_ate_e_times_e_over_e_miller_loop(proof_g_H_precomp, pvk_vk_rC_Z_g2_precomp, proof_g_C_g_precomp, pvk_pp_G2_one_precomp, proof_g_A_g_acc_precomp, proof_g_B_g_precomp); + GT QAP = ppT::final_exponentiation(QAP_miller); + if (QAP != GT::one()) + { + print_indent(); printf("QAP divisibility check failed.\n"); + result = false; + } + leave_block("Check QAP divisibility"); + + enter_block("Check same coefficients were used"); + affine_ate_G1_precomp proof_g_K_precomp = ppT::affine_ate_precompute_G1(proof.g_K); + affine_ate_G1_precomp proof_g_A_g_acc_C_precomp = ppT::affine_ate_precompute_G1((proof.g_A.g + acc) + proof.g_C.g); + Fqk K_miller = ppT::affine_ate_e_times_e_over_e_miller_loop(proof_g_A_g_acc_C_precomp, pvk_vk_gamma_beta_g2_precomp, pvk_vk_gamma_beta_g1_precomp, proof_g_B_g_precomp, proof_g_K_precomp, pvk_vk_gamma_g2_precomp); + GT K = ppT::final_exponentiation(K_miller); + if (K != GT::one()) + { + print_indent(); printf("Same-coefficient check failed.\n"); + result = false; + } + leave_block("Check same coefficients were used"); + + leave_block("Call to r1cs_ppzksnark_affine_verifier_weak_IC"); + + return result; +} + +} // libsnark +#endif // R1CS_PPZKSNARK_TCC_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark_params.hpp b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark_params.hpp new file mode 100644 index 0000000..4054b8e --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark_params.hpp @@ -0,0 +1,34 @@ +/** @file + ***************************************************************************** + + Declaration of public-parameter selector for the R1CS ppzkSNARK. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef R1CS_PPZKSNARK_PARAMS_HPP_ +#define R1CS_PPZKSNARK_PARAMS_HPP_ + +#include "relations/constraint_satisfaction_problems/r1cs/r1cs.hpp" + +namespace libsnark { + +/** + * Below are various template aliases (used for convenience). + */ + +template +using r1cs_ppzksnark_constraint_system = r1cs_constraint_system >; + +template +using r1cs_ppzksnark_primary_input = r1cs_primary_input >; + +template +using r1cs_ppzksnark_auxiliary_input = r1cs_auxiliary_input >; + +} // libsnark + +#endif // R1CS_PPZKSNARK_PARAMS_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/tests/test_r1cs_ppzksnark.cpp b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/tests/test_r1cs_ppzksnark.cpp new file mode 100644 index 0000000..6f8b575 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/tests/test_r1cs_ppzksnark.cpp @@ -0,0 +1,42 @@ +/** @file + ***************************************************************************** + Test program that exercises the ppzkSNARK (first generator, then + prover, then verifier) on a synthetic R1CS instance. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ +#include +#include + +#include "common/default_types/r1cs_ppzksnark_pp.hpp" +#include "common/profiling.hpp" +#include "common/utils.hpp" +#include "relations/constraint_satisfaction_problems/r1cs/examples/r1cs_examples.hpp" +#include "zk_proof_systems/ppzksnark/r1cs_ppzksnark/examples/run_r1cs_ppzksnark.hpp" + +using namespace libsnark; + +template +void test_r1cs_ppzksnark(size_t num_constraints, + size_t input_size) +{ + print_header("(enter) Test R1CS ppzkSNARK"); + + const bool test_serialization = true; + r1cs_example > example = generate_r1cs_example_with_binary_input >(num_constraints, input_size); + const bool bit = run_r1cs_ppzksnark(example, test_serialization); + assert(bit); + + print_header("(leave) Test R1CS ppzkSNARK"); +} + +int main() +{ + default_r1cs_ppzksnark_pp::init_public_params(); + start_profiling(); + + test_r1cs_ppzksnark(1000, 100); +} diff --git a/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/ram_ppzksnark/examples/demo_ram_ppzksnark.cpp b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/ram_ppzksnark/examples/demo_ram_ppzksnark.cpp new file mode 100644 index 0000000..127737f --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/ram_ppzksnark/examples/demo_ram_ppzksnark.cpp @@ -0,0 +1,179 @@ +/** + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ +#include +#include +#include +#include +#include +#ifndef MINDEPS +#include +#endif + +#include "common/default_types/tinyram_ppzksnark_pp.hpp" +#include "common/profiling.hpp" +#include "reductions/ram_to_r1cs/ram_to_r1cs.hpp" +#include "zk_proof_systems/ppzksnark/ram_ppzksnark/ram_ppzksnark.hpp" +#include "relations/ram_computations/rams/tinyram/tinyram_params.hpp" + +#ifndef MINDEPS +namespace po = boost::program_options; + +bool process_demo_command_line(const int argc, const char** argv, + std::string &assembly_fn, + std::string &processed_assembly_fn, + std::string &architecture_params_fn, + std::string &computation_bounds_fn, + std::string &primary_input_fn, + std::string &auxiliary_input_fn) +{ + try + { + po::options_description desc("Usage"); + desc.add_options() + ("help", "print this help message") + ("assembly", po::value(&assembly_fn)->required()) + ("processed_assembly", po::value(&processed_assembly_fn)->required()) + ("architecture_params", po::value(&architecture_params_fn)->required()) + ("computation_bounds", po::value(&computation_bounds_fn)->required()) + ("primary_input", po::value(&primary_input_fn)->required()) + ("auxiliary_input", po::value(&auxiliary_input_fn)->required()); + + po::variables_map vm; + po::store(po::parse_command_line(argc, argv, desc), vm); + + if (vm.count("help")) + { + std::cout << desc << "\n"; + return false; + } + + po::notify(vm); + } + catch(std::exception& e) + { + std::cerr << "Error: " << e.what() << "\n"; + return false; + } + + return true; +} +#endif + +using namespace libsnark; + +int main(int argc, const char * argv[]) +{ + default_tinyram_ppzksnark_pp::init_public_params(); +#ifdef MINDEPS + std::string assembly_fn = "assembly.s"; + std::string processed_assembly_fn = "processed.txt"; + std::string architecture_params_fn = "architecture_params.txt"; + std::string computation_bounds_fn = "computation_bounds.txt"; + std::string primary_input_fn = "primary_input.txt"; + std::string auxiliary_input_fn = "auxiliary_input.txt"; +#else + std::string assembly_fn; + std::string processed_assembly_fn; + std::string architecture_params_fn; + std::string computation_bounds_fn; + std::string primary_input_fn; + std::string auxiliary_input_fn; + + if (!process_demo_command_line(argc, argv, assembly_fn, processed_assembly_fn, architecture_params_fn, + computation_bounds_fn, primary_input_fn, auxiliary_input_fn)) + { + return 1; + } +#endif + start_profiling(); + + printf("================================================================================\n"); + printf("TinyRAM example loader\n"); + printf("================================================================================\n\n"); + + /* load everything */ + ram_ppzksnark_architecture_params ap; + std::ifstream f_ap(architecture_params_fn); + f_ap >> ap; + + printf("Will run on %zu register machine (word size = %zu)\n", ap.k, ap.w); + + std::ifstream f_rp(computation_bounds_fn); + size_t tinyram_input_size_bound, tinyram_program_size_bound, time_bound; + f_rp >> tinyram_input_size_bound >> tinyram_program_size_bound >> time_bound; + + std::ifstream processed(processed_assembly_fn); + std::ifstream raw(assembly_fn); + tinyram_program program = load_preprocessed_program(ap, processed); + + printf("Program:\n%s\n", std::string((std::istreambuf_iterator(raw)), + std::istreambuf_iterator()).c_str()); + + std::ifstream f_primary_input(primary_input_fn); + std::ifstream f_auxiliary_input(auxiliary_input_fn); + + enter_block("Loading primary input"); + tinyram_input_tape primary_input = load_tape(f_primary_input); + leave_block("Loading primary input"); + + enter_block("Loading auxiliary input"); + tinyram_input_tape auxiliary_input = load_tape(f_auxiliary_input); + leave_block("Loading auxiliary input"); + + printf("\nPress enter to continue.\n"); + std::cin.get(); + + const size_t boot_trace_size_bound = tinyram_program_size_bound + tinyram_input_size_bound; + const ram_boot_trace boot_trace = tinyram_boot_trace_from_program_and_input(ap, boot_trace_size_bound, program, primary_input); + + printf("================================================================================\n"); + printf("TinyRAM arithmetization test for T = %zu time steps\n", time_bound); + printf("================================================================================\n\n"); + + typedef ram_ppzksnark_machine_pp default_ram; + typedef ram_base_field FieldT; + + ram_to_r1cs r(ap, boot_trace_size_bound, time_bound); + r.instance_map(); + + const r1cs_primary_input r1cs_primary_input = ram_to_r1cs::primary_input_map(ap, boot_trace_size_bound, boot_trace); + const r1cs_auxiliary_input r1cs_auxiliary_input = r.auxiliary_input_map(boot_trace, auxiliary_input); + const r1cs_constraint_system constraint_system = r.get_constraint_system(); + + r.print_execution_trace(); + assert(constraint_system.is_satisfied(r1cs_primary_input, r1cs_auxiliary_input)); + + printf("\nPress enter to continue.\n"); + std::cin.get(); + + printf("================================================================================\n"); + printf("TinyRAM ppzkSNARK Key Pair Generator\n"); + printf("================================================================================\n\n"); + const ram_ppzksnark_keypair keypair = ram_ppzksnark_generator(ap, boot_trace_size_bound, time_bound); + + printf("\nPress enter to continue.\n"); + std::cin.get(); + + printf("================================================================================\n"); + printf("TinyRAM ppzkSNARK Prover\n"); + printf("================================================================================\n\n"); + const ram_ppzksnark_proof proof = ram_ppzksnark_prover(keypair.pk, boot_trace, auxiliary_input); + + printf("\nPress enter to continue.\n"); + std::cin.get(); + + printf("================================================================================\n"); + printf("TinyRAM ppzkSNARK Verifier\n"); + printf("================================================================================\n\n"); + bool bit = ram_ppzksnark_verifier(keypair.vk, boot_trace, proof); + + printf("================================================================================\n"); + printf("The verification result is: %s\n", (bit ? "PASS" : "FAIL")); + printf("================================================================================\n"); + print_mem(); + printf("================================================================================\n"); +} diff --git a/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/ram_ppzksnark/examples/demo_ram_ppzksnark_generator.cpp b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/ram_ppzksnark/examples/demo_ram_ppzksnark_generator.cpp new file mode 100644 index 0000000..c684981 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/ram_ppzksnark/examples/demo_ram_ppzksnark_generator.cpp @@ -0,0 +1,101 @@ +/** + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ +#include +#include +#ifndef MINDEPS +#include +#endif + +#include "common/default_types/ram_ppzksnark_pp.hpp" +#include "zk_proof_systems/ppzksnark/ram_ppzksnark/ram_ppzksnark.hpp" +#include "relations/ram_computations/rams/tinyram/tinyram_params.hpp" + +#ifndef MINDEPS +namespace po = boost::program_options; + +bool process_generator_command_line(const int argc, const char** argv, + std::string &architecture_params_fn, + std::string &computation_bounds_fn, + std::string &proving_key_fn, + std::string &verification_key_fn) +{ + try + { + po::options_description desc("Usage"); + desc.add_options() + ("help", "print this help message") + ("architecture_params", po::value(&architecture_params_fn)->required()) + ("computation_bounds", po::value(&computation_bounds_fn)->required()) + ("proving_key", po::value(&proving_key_fn)->required()) + ("verification_key", po::value(&verification_key_fn)->required()); + + po::variables_map vm; + po::store(po::parse_command_line(argc, argv, desc), vm); + + if (vm.count("help")) + { + std::cout << desc << "\n"; + return false; + } + + po::notify(vm); + } + catch(std::exception& e) + { + std::cerr << "Error: " << e.what() << "\n"; + return false; + } + + return true; +} +#endif + +using namespace libsnark; + +int main(int argc, const char * argv[]) +{ + ram_ppzksnark_snark_pp::init_public_params(); +#ifdef MINDEPS + std::string architecture_params_fn = "architecture_params.txt"; + std::string computation_bounds_fn = "computation_bounds.txt"; + std::string proving_key_fn = "proving_key.txt"; + std::string verification_key_fn = "verification_key.txt"; +#else + std::string architecture_params_fn; + std::string computation_bounds_fn; + std::string proving_key_fn; + std::string verification_key_fn; + + if (!process_generator_command_line(argc, argv, architecture_params_fn, computation_bounds_fn, + proving_key_fn, verification_key_fn)) + { + return 1; + } +#endif + start_profiling(); + + /* load everything */ + ram_ppzksnark_architecture_params ap; + std::ifstream f_ap(architecture_params_fn); + f_ap >> ap; + + std::ifstream f_rp(computation_bounds_fn); + size_t tinyram_input_size_bound, tinyram_program_size_bound, time_bound; + f_rp >> tinyram_input_size_bound >> tinyram_program_size_bound >> time_bound; + + const size_t boot_trace_size_bound = tinyram_program_size_bound + tinyram_input_size_bound; + + const ram_ppzksnark_keypair keypair = ram_ppzksnark_generator(ap, boot_trace_size_bound, time_bound); + + std::ofstream pk(proving_key_fn); + pk << keypair.pk; + pk.close(); + + std::ofstream vk(verification_key_fn); + vk << keypair.vk; + vk.close(); +} diff --git a/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/ram_ppzksnark/examples/demo_ram_ppzksnark_prover.cpp b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/ram_ppzksnark/examples/demo_ram_ppzksnark_prover.cpp new file mode 100644 index 0000000..9e54755 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/ram_ppzksnark/examples/demo_ram_ppzksnark_prover.cpp @@ -0,0 +1,106 @@ +/** + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ +#include +#include +#ifndef MINDEPS +#include +#endif + +#include "common/default_types/tinyram_ppzksnark_pp.hpp" +#include "zk_proof_systems/ppzksnark/ram_ppzksnark/ram_ppzksnark.hpp" +#include "relations/ram_computations/rams/tinyram/tinyram_params.hpp" + +#ifndef MINDEPS +namespace po = boost::program_options; + +bool process_prover_command_line(const int argc, const char** argv, + std::string &processed_assembly_fn, + std::string &proving_key_fn, + std::string &primary_input_fn, + std::string &auxiliary_input_fn, + std::string &proof_fn) +{ + try + { + po::options_description desc("Usage"); + desc.add_options() + ("help", "print this help message") + ("processed_assembly", po::value(&processed_assembly_fn)->required()) + ("proving_key", po::value(&proving_key_fn)->required()) + ("primary_input", po::value(&primary_input_fn)->required()) + ("auxiliary_input", po::value(&auxiliary_input_fn)->required()) + ("proof", po::value(&proof_fn)->required()); + + po::variables_map vm; + po::store(po::parse_command_line(argc, argv, desc), vm); + + if (vm.count("help")) + { + std::cout << desc << "\n"; + return false; + } + + po::notify(vm); + } + catch(std::exception& e) + { + std::cerr << "Error: " << e.what() << "\n"; + return false; + } + + return true; +} +#endif + +using namespace libsnark; + +int main(int argc, const char * argv[]) +{ + default_tinyram_ppzksnark_pp::init_public_params(); + +#ifdef MINDEPS + std::string processed_assembly_fn = "processed.txt"; + std::string proving_key_fn = "proving_key.txt"; + std::string primary_input_fn = "primary_input.txt"; + std::string auxiliary_input_fn = "auxiliary_input.txt"; + std::string proof_fn = "proof.txt"; +#else + std::string processed_assembly_fn; + std::string proving_key_fn; + std::string primary_input_fn; + std::string auxiliary_input_fn; + std::string proof_fn; + + if (!process_prover_command_line(argc, argv, processed_assembly_fn, + proving_key_fn, primary_input_fn, auxiliary_input_fn, proof_fn)) + { + return 1; + } +#endif + start_profiling(); + + /* load everything */ + ram_ppzksnark_proving_key pk; + std::ifstream pk_file(proving_key_fn); + pk_file >> pk; + pk_file.close(); + + std::ifstream processed(processed_assembly_fn); + tinyram_program program = load_preprocessed_program(pk.ap, processed); + + std::ifstream f_primary_input(primary_input_fn); + std::ifstream f_auxiliary_input(auxiliary_input_fn); + tinyram_input_tape primary_input = load_tape(f_primary_input); + tinyram_input_tape auxiliary_input = load_tape(f_auxiliary_input); + + const ram_boot_trace boot_trace = tinyram_boot_trace_from_program_and_input(pk.ap, pk.primary_input_size_bound, program, primary_input); + const ram_ppzksnark_proof proof = ram_ppzksnark_prover(pk, boot_trace, auxiliary_input); + + std::ofstream proof_file(proof_fn); + proof_file << proof; + proof_file.close(); +} diff --git a/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/ram_ppzksnark/examples/demo_ram_ppzksnark_verifier.cpp b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/ram_ppzksnark/examples/demo_ram_ppzksnark_verifier.cpp new file mode 100644 index 0000000..33e411c --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/ram_ppzksnark/examples/demo_ram_ppzksnark_verifier.cpp @@ -0,0 +1,110 @@ +/** + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ +#include +#include +#ifndef MINDEPS +#include +#endif + +#include "common/default_types/tinyram_ppzksnark_pp.hpp" +#include "zk_proof_systems/ppzksnark/ram_ppzksnark/ram_ppzksnark.hpp" +#include "relations/ram_computations/rams/tinyram/tinyram_params.hpp" + +#ifndef MINDEPS +namespace po = boost::program_options; + +bool process_verifier_command_line(const int argc, const char** argv, + std::string &processed_assembly_fn, + std::string &verification_key_fn, + std::string &primary_input_fn, + std::string &proof_fn, + std::string &verification_result_fn) +{ + try + { + po::options_description desc("Usage"); + desc.add_options() + ("help", "print this help message") + ("processed_assembly", po::value(&processed_assembly_fn)->required()) + ("verification_key", po::value(&verification_key_fn)->required()) + ("primary_input", po::value(&primary_input_fn)->required()) + ("proof", po::value(&proof_fn)->required()) + ("verification_result", po::value(&verification_result_fn)->required()); + + po::variables_map vm; + po::store(po::parse_command_line(argc, argv, desc), vm); + + if (vm.count("help")) + { + std::cout << desc << "\n"; + return false; + } + + po::notify(vm); + } + catch(std::exception& e) + { + std::cerr << "Error: " << e.what() << "\n"; + return false; + } + + return true; +} +#endif + +using namespace libsnark; + +int main(int argc, const char * argv[]) +{ + default_tinyram_ppzksnark_pp::init_public_params(); + +#ifdef MINDEPS + std::string processed_assembly_fn = "processed.txt"; + std::string verification_key_fn = "verification_key.txt"; + std::string proof_fn = "proof.txt"; + std::string primary_input_fn = "primary_input.txt"; + std::string verification_result_fn = "verification_result.txt"; +#else + std::string processed_assembly_fn; + std::string verification_key_fn; + std::string proof_fn; + std::string primary_input_fn; + std::string verification_result_fn; + + if (!process_verifier_command_line(argc, argv, processed_assembly_fn, verification_key_fn, primary_input_fn, proof_fn, verification_result_fn)) + { + return 1; + } +#endif + start_profiling(); + + ram_ppzksnark_verification_key vk; + std::ifstream vk_file(verification_key_fn); + vk_file >> vk; + vk_file.close(); + + std::ifstream processed(processed_assembly_fn); + tinyram_program program = load_preprocessed_program(vk.ap, processed); + + std::ifstream f_primary_input(primary_input_fn); + tinyram_input_tape primary_input = load_tape(f_primary_input); + + std::ifstream proof_file(proof_fn); + ram_ppzksnark_proof pi; + proof_file >> pi; + proof_file.close(); + + const ram_boot_trace boot_trace = tinyram_boot_trace_from_program_and_input(vk.ap, vk.primary_input_size_bound, program, primary_input); + const bool bit = ram_ppzksnark_verifier(vk, boot_trace, pi); + + printf("================================================================================\n"); + printf("The verification result is: %s\n", (bit ? "PASS" : "FAIL")); + printf("================================================================================\n"); + std::ofstream vr_file(verification_result_fn); + vr_file << bit << "\n"; + vr_file.close(); +} diff --git a/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/ram_ppzksnark/examples/run_ram_ppzksnark.hpp b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/ram_ppzksnark/examples/run_ram_ppzksnark.hpp new file mode 100644 index 0000000..5bb4747 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/ram_ppzksnark/examples/run_ram_ppzksnark.hpp @@ -0,0 +1,36 @@ +/** @file + ***************************************************************************** + + Declaration of functionality that runs the RAM ppzkSNARK for + a given RAM example. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef RUN_RAM_PPZKSNARK_HPP_ +#define RUN_RAM_PPZKSNARK_HPP_ + +#include "relations/ram_computations/rams/examples/ram_examples.hpp" +#include "zk_proof_systems/ppzksnark/ram_ppzksnark/ram_ppzksnark_params.hpp" + +namespace libsnark { + +/** + * Runs the ppzkSNARK (generator, prover, and verifier) for a given + * RAM example (specified by an architecture, boot trace, auxiliary input, and time bound). + * + * Optionally, also test the serialization routines for keys and proofs. + * (This takes additional time.) + */ +template +bool run_ram_ppzksnark(const ram_example > &example, + const bool test_serialization); + +} // libsnark + +#include "zk_proof_systems/ppzksnark/ram_ppzksnark/examples/run_ram_ppzksnark.tcc" + +#endif // RUN_RAM_PPZKSNARK_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/ram_ppzksnark/examples/run_ram_ppzksnark.tcc b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/ram_ppzksnark/examples/run_ram_ppzksnark.tcc new file mode 100644 index 0000000..b1cf2b8 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/ram_ppzksnark/examples/run_ram_ppzksnark.tcc @@ -0,0 +1,85 @@ +/** @file + ***************************************************************************** + + Implementation of functionality that runs the RAM ppzkSNARK for + a given RAM example. + + See run_ram_ppzksnark.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef RUN_RAM_PPZKSNARK_TCC_ +#define RUN_RAM_PPZKSNARK_TCC_ + +#include "zk_proof_systems/ppzksnark/ram_ppzksnark/ram_ppzksnark.hpp" + +#include + +#include "common/profiling.hpp" + +namespace libsnark { + +/** + * The code below provides an example of all stages of running a RAM ppzkSNARK. + * + * Of course, in a real-life scenario, we would have three distinct entities, + * mangled into one in the demonstration below. The three entities are as follows. + * (1) The "generator", which runs the ppzkSNARK generator on input a given + * architecture and bounds on the computation. + * (2) The "prover", which runs the ppzkSNARK prover on input the proving key, + * a boot trace, and an auxiliary input. + * (3) The "verifier", which runs the ppzkSNARK verifier on input the verification key, + * a boot trace, and a proof. + */ +template +bool run_ram_ppzksnark(const ram_example > &example, + const bool test_serialization) +{ + enter_block("Call to run_ram_ppzksnark"); + + printf("This run uses an example with the following parameters:\n"); + example.ap.print(); + printf("* Primary input size bound (L): %zu\n", example.boot_trace_size_bound); + printf("* Time bound (T): %zu\n", example.time_bound); + printf("Hence, log2(L+2*T) equals %zu\n", log2(example.boot_trace_size_bound+2*example.time_bound)); + + print_header("RAM ppzkSNARK Generator"); + ram_ppzksnark_keypair keypair = ram_ppzksnark_generator(example.ap, example.boot_trace_size_bound, example.time_bound); + printf("\n"); print_indent(); print_mem("after generator"); + + if (test_serialization) + { + enter_block("Test serialization of keys"); + keypair.pk = reserialize >(keypair.pk); + keypair.vk = reserialize >(keypair.vk); + leave_block("Test serialization of keys"); + } + + print_header("RAM ppzkSNARK Prover"); + ram_ppzksnark_proof proof = ram_ppzksnark_prover(keypair.pk, example.boot_trace, example.auxiliary_input); + printf("\n"); print_indent(); print_mem("after prover"); + + if (test_serialization) + { + enter_block("Test serialization of proof"); + proof = reserialize >(proof); + leave_block("Test serialization of proof"); + } + + print_header("RAM ppzkSNARK Verifier"); + bool ans = ram_ppzksnark_verifier(keypair.vk, example.boot_trace, proof); + printf("\n"); print_indent(); print_mem("after verifier"); + printf("* The verification result is: %s\n", (ans ? "PASS" : "FAIL")); + + leave_block("Call to run_ram_ppzksnark"); + + return ans; +} + +} // libsnark + +#endif // RUN_RAM_PPZKSNARK_TCC_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/ram_ppzksnark/profiling/profile_ram_ppzksnark.cpp b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/ram_ppzksnark/profiling/profile_ram_ppzksnark.cpp new file mode 100644 index 0000000..856f9ab --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/ram_ppzksnark/profiling/profile_ram_ppzksnark.cpp @@ -0,0 +1,59 @@ +/** + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ +#include +#include +#include +#include +#include +#include + +#include "common/default_types/ram_ppzksnark_pp.hpp" +#include "common/profiling.hpp" +#include "relations/ram_computations/rams/examples/ram_examples.hpp" +#include "zk_proof_systems/ppzksnark/ram_ppzksnark/examples/run_ram_ppzksnark.hpp" +#include "relations/ram_computations/rams/tinyram/tinyram_params.hpp" + +using namespace libsnark; + +int main(int argc, const char * argv[]) +{ + ram_ppzksnark_snark_pp::init_public_params(); + start_profiling(); + + if (argc == 2 && strcmp(argv[1], "-v") == 0) + { + print_compilation_info(); + return 0; + } + + if (argc != 6) + { + printf("usage: %s word_size reg_count program_size input_size time_bound\n", argv[0]); + return 1; + } + + const size_t w = atoi(argv[1]), + k = atoi(argv[2]), + program_size = atoi(argv[3]), + input_size = atoi(argv[4]), + time_bound = atoi(argv[5]); + + typedef ram_ppzksnark_machine_pp machine_ppT; + + const ram_ppzksnark_architecture_params ap(w, k); + + enter_block("Generate RAM example"); + const size_t boot_trace_size_bound = program_size + input_size; + const bool satisfiable = true; + ram_example example = gen_ram_example_complex(ap, boot_trace_size_bound, time_bound, satisfiable); + enter_block("Generate RAM example"); + + print_header("(enter) Profile RAM ppzkSNARK"); + const bool test_serialization = true; + run_ram_ppzksnark(example, test_serialization); + print_header("(leave) Profile RAM ppzkSNARK"); +} diff --git a/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/ram_ppzksnark/ram_ppzksnark.hpp b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/ram_ppzksnark/ram_ppzksnark.hpp new file mode 100644 index 0000000..7950277 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/ram_ppzksnark/ram_ppzksnark.hpp @@ -0,0 +1,227 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for a ppzkSNARK for RAM. + + This includes: + - the class for a proving key; + - the class for a verification key; + - the class for a key pair (proving key & verification key); + - the class for a proof; + - the generator algorithm; + - the prover algorithm; + - the verifier algorithm. + + The implementation follows, extends, and optimizes the approach described + in \[BCTV14] (itself building on \[BCGTV13]). In particular, the ppzkSNARK + for RAM is constructed from a ppzkSNARK for R1CS. + + + Acronyms: + + "R1CS" = "Rank-1 Constraint Systems" + "RAM" = "Random-Access Machines" + "ppzkSNARK" = "Pre-Processing Zero-Knowledge Succinct Non-interactive ARgument of Knowledge" + + References: + + \[BCGTV13]: + "SNARKs for C: verifying program executions succinctly and in zero knowledge", + Eli Ben-Sasson, Alessandro Chiesa, Daniel Genkin, Eran Tromer, Madars Virza, + CRYPTO 2014, + + + \[BCTV14]: + "Succinct Non-Interactive Zero Knowledge for a von Neumann Architecture", + Eli Ben-Sasson, Alessandro Chiesa, Eran Tromer, Madars Virza, + USENIX Security 2014, + + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef RAM_PPZKSNARK_HPP_ +#define RAM_PPZKSNARK_HPP_ + +#include + +#include "reductions/ram_to_r1cs/ram_to_r1cs.hpp" +#include "zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.hpp" +#include "zk_proof_systems/ppzksnark/ram_ppzksnark/ram_ppzksnark_params.hpp" + +namespace libsnark { + +/******************************** Proving key ********************************/ + +template +class ram_ppzksnark_proving_key; + +template +std::ostream& operator<<(std::ostream &out, const ram_ppzksnark_proving_key &pk); + +template +std::istream& operator>>(std::istream &in, ram_ppzksnark_proving_key &pk); + +/** + * A proving key for the RAM ppzkSNARK. + */ +template +class ram_ppzksnark_proving_key { +public: + typedef ram_ppzksnark_snark_pp snark_ppT; + + r1cs_ppzksnark_proving_key r1cs_pk; + ram_ppzksnark_architecture_params ap; + size_t primary_input_size_bound; + size_t time_bound; + + ram_ppzksnark_proving_key() {} + ram_ppzksnark_proving_key(const ram_ppzksnark_proving_key &other) = default; + ram_ppzksnark_proving_key(ram_ppzksnark_proving_key &&other) = default; + ram_ppzksnark_proving_key(r1cs_ppzksnark_proving_key &&r1cs_pk, + const ram_ppzksnark_architecture_params &ap, + const size_t primary_input_size_bound, + const size_t time_bound) : + r1cs_pk(std::move(r1cs_pk)), + ap(ap), + primary_input_size_bound(primary_input_size_bound), + time_bound(time_bound) + {} + + ram_ppzksnark_proving_key& operator=(const ram_ppzksnark_proving_key &other) = default; + + bool operator==(const ram_ppzksnark_proving_key &other) const; + friend std::ostream& operator<< (std::ostream &out, const ram_ppzksnark_proving_key &pk); + friend std::istream& operator>> (std::istream &in, ram_ppzksnark_proving_key &pk); +}; + + +/******************************* Verification key ****************************/ + +template +class ram_ppzksnark_verification_key; + +template +std::ostream& operator<<(std::ostream &out, const ram_ppzksnark_verification_key &vk); + +template +std::istream& operator>>(std::istream &in, ram_ppzksnark_verification_key &vk); + +/** + * A verification key for the RAM ppzkSNARK. + */ +template +class ram_ppzksnark_verification_key { +public: + typedef ram_ppzksnark_snark_pp snark_ppT; + + r1cs_ppzksnark_verification_key r1cs_vk; + ram_ppzksnark_architecture_params ap; + size_t primary_input_size_bound; + size_t time_bound; + + std::set bound_primary_input_locations; + + ram_ppzksnark_verification_key() = default; + ram_ppzksnark_verification_key(const ram_ppzksnark_verification_key &other) = default; + ram_ppzksnark_verification_key(ram_ppzksnark_verification_key &&other) = default; + ram_ppzksnark_verification_key(const r1cs_ppzksnark_verification_key &r1cs_vk, + const ram_ppzksnark_architecture_params &ap, + const size_t primary_input_size_bound, + const size_t time_bound) : + r1cs_vk(r1cs_vk), + ap(ap), + primary_input_size_bound(primary_input_size_bound), + time_bound(time_bound) + {} + + ram_ppzksnark_verification_key& operator=(const ram_ppzksnark_verification_key &other) = default; + + ram_ppzksnark_verification_key bind_primary_input(const ram_ppzksnark_primary_input &primary_input) const; + + bool operator==(const ram_ppzksnark_verification_key &other) const; + friend std::ostream& operator<< (std::ostream &out, const ram_ppzksnark_verification_key &vk); + friend std::istream& operator>> (std::istream &in, ram_ppzksnark_verification_key &vk); +}; + + +/********************************** Key pair *********************************/ + +/** + * A key pair for the RAM ppzkSNARK, which consists of a proving key and a verification key. + */ +template +struct ram_ppzksnark_keypair { +public: + ram_ppzksnark_proving_key pk; + ram_ppzksnark_verification_key vk; + + ram_ppzksnark_keypair() = default; + ram_ppzksnark_keypair(ram_ppzksnark_keypair &&other) = default; + ram_ppzksnark_keypair(const ram_ppzksnark_keypair &other) = default; + ram_ppzksnark_keypair(ram_ppzksnark_proving_key &&pk, + ram_ppzksnark_verification_key &&vk) : + pk(std::move(pk)), + vk(std::move(vk)) + {} +}; + + +/*********************************** Proof ***********************************/ + +/** + * A proof for the RAM ppzkSNARK. + */ +template +using ram_ppzksnark_proof = r1cs_ppzksnark_proof >; + + +/***************************** Main algorithms *******************************/ + +/** + * A generator algorithm for the RAM ppzkSNARK. + * + * Given a choice of architecture parameters and computation bounds, this algorithm + * produces proving and verification keys for all computations that respect these choices. + */ +template +ram_ppzksnark_keypair ram_ppzksnark_generator(const ram_ppzksnark_architecture_params &ap, + const size_t primary_input_size_bound, + const size_t time_bound); + +/** + * A prover algorithm for the RAM ppzkSNARK. + * + * Given a proving key, primary input X, and auxiliary input Y, this algorithm + * produces a proof (of knowledge) that attests to the following statement: + * ``there exists Y such that X(Y) accepts''. + * + * Above, it has to be the case that the computation respects the bounds: + * - the size of X is at most primary_input_size_bound, and + * - the time to compute X(Y) is at most time_bound. + */ +template +ram_ppzksnark_proof ram_ppzksnark_prover(const ram_ppzksnark_proving_key &pk, + const ram_ppzksnark_primary_input &primary_input, + const ram_ppzksnark_auxiliary_input &auxiliary_input); + +/** + * A verifier algorithm for the RAM ppzkSNARK. + * + * This algorithm is universal in the sense that the verification key + * supports proof verification for any choice of primary input + * provided that the computation respects the bounds. + */ +template +bool ram_ppzksnark_verifier(const ram_ppzksnark_verification_key &vk, + const ram_ppzksnark_primary_input &primary_input, + const ram_ppzksnark_proof &proof); + +} // libsnark + +#include "zk_proof_systems/ppzksnark/ram_ppzksnark/ram_ppzksnark.tcc" + +#endif // RAM_PPZKSNARK_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/ram_ppzksnark/ram_ppzksnark.tcc b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/ram_ppzksnark/ram_ppzksnark.tcc new file mode 100644 index 0000000..e46a805 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/ram_ppzksnark/ram_ppzksnark.tcc @@ -0,0 +1,178 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for a ppzkSNARK for RAM. + + See ram_ppzksnark.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef RAM_PPZKSNARK_TCC_ +#define RAM_PPZKSNARK_TCC_ + +#include "common/profiling.hpp" +#include "reductions/ram_to_r1cs/ram_to_r1cs.hpp" + +namespace libsnark { + +template +bool ram_ppzksnark_proving_key::operator==(const ram_ppzksnark_proving_key &other) const +{ + return (this->r1cs_pk == other.r1cs_pk && + this->ap == other.ap && + this->primary_input_size_bound == other.primary_input_size_bound && + this->time_bound == other.time_bound); +} + +template +std::ostream& operator<<(std::ostream &out, const ram_ppzksnark_proving_key &pk) +{ + out << pk.r1cs_pk; + out << pk.ap; + out << pk.primary_input_size_bound << "\n"; + out << pk.time_bound << "\n"; + + return out; +} + +template +std::istream& operator>>(std::istream &in, ram_ppzksnark_proving_key &pk) +{ + in >> pk.r1cs_pk; + in >> pk.ap; + in >> pk.primary_input_size_bound; + consume_newline(in); + in >> pk.time_bound; + consume_newline(in); + + return in; +} + +template +ram_ppzksnark_verification_key ram_ppzksnark_verification_key::bind_primary_input(const ram_ppzksnark_primary_input &primary_input) const +{ + typedef ram_ppzksnark_machine_pp ram_ppT; + typedef ram_base_field FieldT; + + enter_block("Call to ram_ppzksnark_verification_key::bind_primary_input"); + ram_ppzksnark_verification_key result(*this); + + const size_t packed_input_element_size = ram_universal_gadget::packed_input_element_size(ap); + + for (auto it : primary_input.get_all_trace_entries()) + { + const size_t input_pos = it.first; + const address_and_value av = it.second; + + assert(input_pos < primary_input_size_bound); + assert(result.bound_primary_input_locations.find(input_pos) == result.bound_primary_input_locations.end()); + + const std::vector packed_input_element = ram_to_r1cs::pack_primary_input_address_and_value(ap, av); + result.r1cs_vk.encoded_IC_query = result.r1cs_vk.encoded_IC_query.template accumulate_chunk(packed_input_element.begin(), packed_input_element.end(), packed_input_element_size * (primary_input_size_bound - 1 - input_pos)); + + result.bound_primary_input_locations.insert(input_pos); + } + + leave_block("Call to ram_ppzksnark_verification_key::bind_primary_input"); + return result; +} + +template +bool ram_ppzksnark_verification_key::operator==(const ram_ppzksnark_verification_key &other) const +{ + return (this->r1cs_vk == other.r1cs_vk && + this->ap == other.ap && + this->primary_input_size_bound == other.primary_input_size_bound && + this->time_bound == other.time_bound); +} + +template +std::ostream& operator<<(std::ostream &out, const ram_ppzksnark_verification_key &vk) +{ + out << vk.r1cs_vk; + out << vk.ap; + out << vk.primary_input_size_bound << "\n"; + out << vk.time_bound << "\n"; + + return out; +} + +template +std::istream& operator>>(std::istream &in, ram_ppzksnark_verification_key &vk) +{ + in >> vk.r1cs_vk; + in >> vk.ap; + in >> vk.primary_input_size_bound; + consume_newline(in); + in >> vk.time_bound; + consume_newline(in); + + return in; +} + +template +ram_ppzksnark_keypair ram_ppzksnark_generator(const ram_ppzksnark_architecture_params &ap, + const size_t primary_input_size_bound, + const size_t time_bound) +{ + typedef ram_ppzksnark_machine_pp ram_ppT; + typedef ram_ppzksnark_snark_pp snark_ppT; + + enter_block("Call to ram_ppzksnark_generator"); + ram_to_r1cs universal_r1cs(ap, primary_input_size_bound, time_bound); + universal_r1cs.instance_map(); + r1cs_ppzksnark_keypair ppzksnark_keypair = r1cs_ppzksnark_generator(universal_r1cs.get_constraint_system()); + leave_block("Call to ram_ppzksnark_generator"); + + ram_ppzksnark_proving_key pk = ram_ppzksnark_proving_key(std::move(ppzksnark_keypair.pk), ap, primary_input_size_bound, time_bound); + ram_ppzksnark_verification_key vk = ram_ppzksnark_verification_key(std::move(ppzksnark_keypair.vk), ap, primary_input_size_bound, time_bound); + + return ram_ppzksnark_keypair(std::move(pk), std::move(vk)); +} + +template +ram_ppzksnark_proof ram_ppzksnark_prover(const ram_ppzksnark_proving_key &pk, + const ram_ppzksnark_primary_input &primary_input, + const ram_ppzksnark_auxiliary_input &auxiliary_input) +{ + typedef ram_ppzksnark_machine_pp ram_ppT; + typedef ram_ppzksnark_snark_pp snark_ppT; + typedef Fr FieldT; + + enter_block("Call to ram_ppzksnark_prover"); + ram_to_r1cs universal_r1cs(pk.ap, pk.primary_input_size_bound, pk.time_bound); + const r1cs_primary_input r1cs_primary_input = ram_to_r1cs::primary_input_map(pk.ap, pk.primary_input_size_bound, primary_input); + + const r1cs_auxiliary_input r1cs_auxiliary_input = universal_r1cs.auxiliary_input_map(primary_input, auxiliary_input); +#if DEBUG + universal_r1cs.print_execution_trace(); + universal_r1cs.print_memory_trace(); +#endif + const r1cs_ppzksnark_proof proof = r1cs_ppzksnark_prover(pk.r1cs_pk, r1cs_primary_input, r1cs_auxiliary_input); + leave_block("Call to ram_ppzksnark_prover"); + + return proof; +} + +template +bool ram_ppzksnark_verifier(const ram_ppzksnark_verification_key &vk, + const ram_ppzksnark_primary_input &primary_input, + const ram_ppzksnark_proof &proof) +{ + typedef ram_ppzksnark_snark_pp snark_ppT; + + enter_block("Call to ram_ppzksnark_verifier"); + const ram_ppzksnark_verification_key input_specific_vk = vk.bind_primary_input(primary_input); + const bool ans = r1cs_ppzksnark_verifier_weak_IC(input_specific_vk.r1cs_vk, r1cs_primary_input >(), proof); + leave_block("Call to ram_ppzksnark_verifier"); + + return ans; +} + +} // libsnark + +#endif // RAM_PPZKSNARK_TCC_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/ram_ppzksnark/ram_ppzksnark_params.hpp b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/ram_ppzksnark/ram_ppzksnark_params.hpp new file mode 100644 index 0000000..5a1d04e --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/ram_ppzksnark/ram_ppzksnark_params.hpp @@ -0,0 +1,72 @@ +/** @file + ***************************************************************************** + + Declaration of public-parameter selector for the RAM ppzkSNARK. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef RAM_PPZKSNARK_PARAMS_HPP_ +#define RAM_PPZKSNARK_PARAMS_HPP_ + +namespace libsnark { + +/** + * The interfaces of the RAM ppzkSNARK are templatized via the parameter + * ram_ppzksnark_ppT. When used, the interfaces must be invoked with + * a particular parameter choice; let 'my_ram_ppzksnark_pp' denote this choice. + * + * my_ram_ppzksnark_pp needs to contain typedefs for the typenames + * - snark_pp, and + * - machine_pp. + * as well as a method with the following signature: + * - static void init_public_params(); + * + * For example, if you want to use the types my_snark_pp and my_machine_pp, + * then you could declare my_ram_ppzksnark_pp as follows: + * + * class my_ram_ppzksnark_pp { + * public: + * typedef my_snark_pp snark_pp; + * typedef my_machine_pp machine_pp; + * static void init_public params() + * { + * snark_pp::init_public_params(); // and additional initialization if needed + * } + * }; + * + * Having done the above, my_ram_ppzksnark_pp can be used as a template parameter. + * + * Look for for default_tinyram_ppzksnark_pp in the file + * + * common/default_types/ram_ppzksnark_pp.hpp + * + * for an example of the above steps for the case of "RAM=TinyRAM". + * + */ + +/** + * Below are various template aliases (used for convenience). + */ + +template +using ram_ppzksnark_snark_pp = typename ram_ppzksnark_ppT::snark_pp; + +template +using ram_ppzksnark_machine_pp = typename ram_ppzksnark_ppT::machine_pp; + +template +using ram_ppzksnark_architecture_params = ram_architecture_params >; + +template +using ram_ppzksnark_primary_input = ram_boot_trace >; + +template +using ram_ppzksnark_auxiliary_input = ram_input_tape >; + +} // libsnark + +#endif // RAM_PPZKSNARK_PARAMS_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/ram_ppzksnark/tests/test_ram_ppzksnark.cpp b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/ram_ppzksnark/tests/test_ram_ppzksnark.cpp new file mode 100644 index 0000000..93211d4 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/ram_ppzksnark/tests/test_ram_ppzksnark.cpp @@ -0,0 +1,57 @@ +/** + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ +#include +#include +#include +#include +#include + +#include "common/default_types/ram_ppzksnark_pp.hpp" +#include "common/profiling.hpp" +#include "relations/ram_computations/rams/examples/ram_examples.hpp" +#include "zk_proof_systems/ppzksnark/ram_ppzksnark/examples/run_ram_ppzksnark.hpp" + +using namespace libsnark; + +template +void test_ram_ppzksnark(const size_t w, + const size_t k, + const size_t program_size, + const size_t input_size, + const size_t time_bound) +{ + print_header("(enter) Test RAM ppzkSNARK"); + + typedef ram_ppzksnark_machine_pp machine_ppT; + const size_t boot_trace_size_bound = program_size + input_size; + const bool satisfiable = true; + + const ram_ppzksnark_architecture_params ap(w, k); + const ram_example example = gen_ram_example_complex(ap, boot_trace_size_bound, time_bound, satisfiable); + + const bool test_serialization = true; + const bool bit = run_ram_ppzksnark(example, test_serialization); + assert(bit); + + print_header("(leave) Test RAM ppzkSNARK"); +} + +int main() +{ + ram_ppzksnark_snark_pp::init_public_params(); + start_profiling(); + + const size_t program_size = 100; + const size_t input_size = 2; + const size_t time_bound = 20; + + // 16-bit TinyRAM with 16 registers + test_ram_ppzksnark(16, 16, program_size, input_size, time_bound); + + // 32-bit TinyRAM with 16 registers + test_ram_ppzksnark(32, 16, program_size, input_size, time_bound); +} diff --git a/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/tbcs_ppzksnark/examples/run_tbcs_ppzksnark.hpp b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/tbcs_ppzksnark/examples/run_tbcs_ppzksnark.hpp new file mode 100644 index 0000000..ff4b062 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/tbcs_ppzksnark/examples/run_tbcs_ppzksnark.hpp @@ -0,0 +1,35 @@ +/** @file + ***************************************************************************** + + Declaration of functionality that runs the TBCS ppzkSNARK for + a given TBCS example. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef RUN_TBCS_PPZKSNARK_HPP_ +#define RUN_TBCS_PPZKSNARK_HPP_ + +#include "relations/circuit_satisfaction_problems/tbcs/examples/tbcs_examples.hpp" + +namespace libsnark { + +/** + * Runs the ppzkSNARK (generator, prover, and verifier) for a given + * TBCS example (specified by a circuit, primary input, and auxiliary input). + * + * Optionally, also test the serialization routines for keys and proofs. + * (This takes additional time.) + */ +template +bool run_tbcs_ppzksnark(const tbcs_example &example, + const bool test_serialization); + +} // libsnark + +#include "zk_proof_systems/ppzksnark/tbcs_ppzksnark/examples/run_tbcs_ppzksnark.tcc" + +#endif // RUN_TBCS_PPZKSNARK_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/tbcs_ppzksnark/examples/run_tbcs_ppzksnark.tcc b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/tbcs_ppzksnark/examples/run_tbcs_ppzksnark.tcc new file mode 100644 index 0000000..c67e40b --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/tbcs_ppzksnark/examples/run_tbcs_ppzksnark.tcc @@ -0,0 +1,87 @@ +/** @file + ***************************************************************************** + + Implementation of functionality that runs the TBCS ppzkSNARK for + a given TBCS example. + + See run_tbcs_ppzksnark.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef RUN_TBCS_PPZKSNARK_TCC_ +#define RUN_TBCS_PPZKSNARK_TCC_ + +#include "zk_proof_systems/ppzksnark/tbcs_ppzksnark/tbcs_ppzksnark.hpp" + +#include + +#include "common/profiling.hpp" + +namespace libsnark { + +/** + * The code below provides an example of all stages of running a TBCS ppzkSNARK. + * + * Of course, in a real-life scenario, we would have three distinct entities, + * mangled into one in the demonstration below. The three entities are as follows. + * (1) The "generator", which runs the ppzkSNARK generator on input a given + * circuit C to create a proving and a verification key for C. + * (2) The "prover", which runs the ppzkSNARK prover on input the proving key, + * a primary input for C, and an auxiliary input for C. + * (3) The "verifier", which runs the ppzkSNARK verifier on input the verification key, + * a primary input for C, and a proof. + */ +template +bool run_tbcs_ppzksnark(const tbcs_example &example, + const bool test_serialization) +{ + enter_block("Call to run_tbcs_ppzksnark"); + + print_header("TBCS ppzkSNARK Generator"); + tbcs_ppzksnark_keypair keypair = tbcs_ppzksnark_generator(example.circuit); + printf("\n"); print_indent(); print_mem("after generator"); + + print_header("Preprocess verification key"); + tbcs_ppzksnark_processed_verification_key pvk = tbcs_ppzksnark_verifier_process_vk(keypair.vk); + + if (test_serialization) + { + enter_block("Test serialization of keys"); + keypair.pk = reserialize >(keypair.pk); + keypair.vk = reserialize >(keypair.vk); + pvk = reserialize >(pvk); + leave_block("Test serialization of keys"); + } + + print_header("TBCS ppzkSNARK Prover"); + tbcs_ppzksnark_proof proof = tbcs_ppzksnark_prover(keypair.pk, example.primary_input, example.auxiliary_input); + printf("\n"); print_indent(); print_mem("after prover"); + + if (test_serialization) + { + enter_block("Test serialization of proof"); + proof = reserialize >(proof); + leave_block("Test serialization of proof"); + } + + print_header("TBCS ppzkSNARK Verifier"); + bool ans = tbcs_ppzksnark_verifier_strong_IC(keypair.vk, example.primary_input, proof); + printf("\n"); print_indent(); print_mem("after verifier"); + printf("* The verification result is: %s\n", (ans ? "PASS" : "FAIL")); + + print_header("TBCS ppzkSNARK Online Verifier"); + bool ans2 = tbcs_ppzksnark_online_verifier_strong_IC(pvk, example.primary_input, proof); + assert(ans == ans2); + + leave_block("Call to run_tbcs_ppzksnark"); + + return ans; +} + +} // libsnark + +#endif // RUN_TBCS_PPZKSNARK_TCC_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/tbcs_ppzksnark/profiling/profile_tbcs_ppzksnark.cpp b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/tbcs_ppzksnark/profiling/profile_tbcs_ppzksnark.cpp new file mode 100644 index 0000000..a27cabf --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/tbcs_ppzksnark/profiling/profile_tbcs_ppzksnark.cpp @@ -0,0 +1,58 @@ +/** @file + ***************************************************************************** + Profiling program that exercises the ppzkSNARK (first generator, then prover, + then verifier) on a synthetic TBCS instance. + + The command + + $ src/tbcs_ppzksnark/examples/profile_tbcs_ppzksnark 1000 10 + + exercises the ppzkSNARK (first generator, then prover, then verifier) on an TBCS instance with 1000 gates and an input consisting of 10 bits. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include + +#include "common/default_types/tbcs_ppzksnark_pp.hpp" +#include "common/profiling.hpp" +#include "common/utils.hpp" +#include "relations/circuit_satisfaction_problems/tbcs/examples/tbcs_examples.hpp" +#include "zk_proof_systems/ppzksnark/tbcs_ppzksnark/examples/run_tbcs_ppzksnark.hpp" + +using namespace libsnark; + +int main(int argc, const char * argv[]) +{ + default_tbcs_ppzksnark_pp::init_public_params(); + start_profiling(); + + if (argc == 2 && strcmp(argv[1], "-v") == 0) + { + print_compilation_info(); + return 0; + } + + if (argc != 3) + { + printf("usage: %s num_gates primary_input_size\n", argv[0]); + return 1; + } + const int num_gates = atoi(argv[1]); + int primary_input_size = atoi(argv[2]); + + const size_t auxiliary_input_size = 0; + const size_t num_outputs = num_gates / 2; + + enter_block("Generate TBCS example"); + tbcs_example example = generate_tbcs_example(primary_input_size, auxiliary_input_size, num_gates, num_outputs); + leave_block("Generate TBCS example"); + + print_header("(enter) Profile TBCS ppzkSNARK"); + const bool test_serialization = true; + run_tbcs_ppzksnark(example, test_serialization); + print_header("(leave) Profile TBCS ppzkSNARK"); +} diff --git a/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/tbcs_ppzksnark/tbcs_ppzksnark.hpp b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/tbcs_ppzksnark/tbcs_ppzksnark.hpp new file mode 100644 index 0000000..656a427 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/tbcs_ppzksnark/tbcs_ppzksnark.hpp @@ -0,0 +1,260 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for a ppzkSNARK for TBCS. + + This includes: + - class for proving key + - class for verification key + - class for processed verification key + - class for key pair (proving key & verification key) + - class for proof + - generator algorithm + - prover algorithm + - verifier algorithm (with strong or weak input consistency) + - online verifier algorithm (with strong or weak input consistency) + + The implementation is a straightforward combination of: + (1) a TBCS-to-USCS reduction, and + (2) a ppzkSNARK for USCS. + + + Acronyms: + + - TBCS = "Two-input Boolean Circuit Satisfiability" + - USCS = "Unitary-Square Constraint System" + - ppzkSNARK = "PreProcessing Zero-Knowledge Succinct Non-interactive ARgument of Knowledge" + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef TBCS_PPZKSNARK_HPP_ +#define TBCS_PPZKSNARK_HPP_ + +#include "relations/circuit_satisfaction_problems/tbcs/tbcs.hpp" +#include "zk_proof_systems/ppzksnark/uscs_ppzksnark/uscs_ppzksnark.hpp" +#include "zk_proof_systems/ppzksnark/tbcs_ppzksnark/tbcs_ppzksnark_params.hpp" + +namespace libsnark { + +/******************************** Proving key ********************************/ + +template +class tbcs_ppzksnark_proving_key; + +template +std::ostream& operator<<(std::ostream &out, const tbcs_ppzksnark_proving_key &pk); + +template +std::istream& operator>>(std::istream &in, tbcs_ppzksnark_proving_key &pk); + +/** + * A proving key for the TBCS ppzkSNARK. + */ +template +class tbcs_ppzksnark_proving_key { +public: + typedef Fr FieldT; + + tbcs_ppzksnark_circuit circuit; + uscs_ppzksnark_proving_key uscs_pk; + + tbcs_ppzksnark_proving_key() {}; + tbcs_ppzksnark_proving_key(const tbcs_ppzksnark_proving_key &other) = default; + tbcs_ppzksnark_proving_key(tbcs_ppzksnark_proving_key &&other) = default; + tbcs_ppzksnark_proving_key(const tbcs_ppzksnark_circuit &circuit, + const uscs_ppzksnark_proving_key &uscs_pk) : + circuit(circuit), uscs_pk(uscs_pk) + {} + tbcs_ppzksnark_proving_key(tbcs_ppzksnark_circuit &&circuit, + uscs_ppzksnark_proving_key &&uscs_pk) : + circuit(std::move(circuit)), uscs_pk(std::move(uscs_pk)) + {} + + tbcs_ppzksnark_proving_key& operator=(const tbcs_ppzksnark_proving_key &other) = default; + + size_t G1_size() const + { + return uscs_pk.G1_size(); + } + + size_t G2_size() const + { + return uscs_pk.G2_size(); + } + + size_t G1_sparse_size() const + { + return uscs_pk.G1_sparse_size(); + } + + size_t G2_sparse_size() const + { + return uscs_pk.G2_sparse_size(); + } + + size_t size_in_bits() const + { + return uscs_pk.size_in_bits(); + } + + void print_size() const + { + uscs_pk.print_size(); + } + + bool operator==(const tbcs_ppzksnark_proving_key &other) const; + friend std::ostream& operator<< (std::ostream &out, const tbcs_ppzksnark_proving_key &pk); + friend std::istream& operator>> (std::istream &in, tbcs_ppzksnark_proving_key &pk); +}; + + +/******************************* Verification key ****************************/ + +/** + * A verification key for the TBCS ppzkSNARK. + */ +template +using tbcs_ppzksnark_verification_key = uscs_ppzksnark_verification_key; + + +/************************ Processed verification key *************************/ + +/** + * A processed verification key for the TBCS ppzkSNARK. + * + * Compared to a (non-processed) verification key, a processed verification key + * contains a small constant amount of additional pre-computed information that + * enables a faster verification time. + */ +template +using tbcs_ppzksnark_processed_verification_key = uscs_ppzksnark_processed_verification_key; + + +/********************************** Key pair *********************************/ + +/** + * A key pair for the TBCS ppzkSNARK, which consists of a proving key and a verification key. + */ +template +class tbcs_ppzksnark_keypair { +public: + tbcs_ppzksnark_proving_key pk; + tbcs_ppzksnark_verification_key vk; + + tbcs_ppzksnark_keypair() {}; + tbcs_ppzksnark_keypair(tbcs_ppzksnark_keypair &&other) = default; + tbcs_ppzksnark_keypair(const tbcs_ppzksnark_proving_key &pk, + const tbcs_ppzksnark_verification_key &vk) : + pk(pk), + vk(vk) + {} + + tbcs_ppzksnark_keypair(tbcs_ppzksnark_proving_key &&pk, + tbcs_ppzksnark_verification_key &&vk) : + pk(std::move(pk)), + vk(std::move(vk)) + {} +}; + + +/*********************************** Proof ***********************************/ + +/** + * A proof for the TBCS ppzkSNARK. + */ +template +using tbcs_ppzksnark_proof = uscs_ppzksnark_proof; + + +/***************************** Main algorithms *******************************/ + +/** + * A generator algorithm for the TBCS ppzkSNARK. + * + * Given a TBCS circuit C, this algorithm produces proving and verification keys for C. + */ +template +tbcs_ppzksnark_keypair tbcs_ppzksnark_generator(const tbcs_ppzksnark_circuit &circuit); + +/** + * A prover algorithm for the TBCS ppzkSNARK. + * + * Given a TBCS primary input X and a TBCS auxiliary input Y, this algorithm + * produces a proof (of knowledge) that attests to the following statement: + * ``there exists Y such that C(X,Y)=0''. + * Above, C is the TBCS circuit that was given as input to the generator algorithm. + */ +template +tbcs_ppzksnark_proof tbcs_ppzksnark_prover(const tbcs_ppzksnark_proving_key &pk, + const tbcs_ppzksnark_primary_input &primary_input, + const tbcs_ppzksnark_auxiliary_input &auxiliary_input); + +/* + Below are four variants of verifier algorithm for the TBCS ppzkSNARK. + + These are the four cases that arise from the following two choices: + + (1) The verifier accepts a (non-processed) verification key or, instead, a processed verification key. + In the latter case, we call the algorithm an "online verifier". + + (2) The verifier checks for "weak" input consistency or, instead, "strong" input consistency. + Strong input consistency requires that |primary_input| = C.num_inputs, whereas + weak input consistency requires that |primary_input| <= C.num_inputs (and + the primary input is implicitly padded with zeros up to length C.num_inputs). + */ + +/** + * A verifier algorithm for the TBCS ppzkSNARK that: + * (1) accepts a non-processed verification key, and + * (2) has weak input consistency. + */ +template +bool tbcs_ppzksnark_verifier_weak_IC(const tbcs_ppzksnark_verification_key &vk, + const tbcs_ppzksnark_primary_input &primary_input, + const tbcs_ppzksnark_proof &proof); + +/** + * A verifier algorithm for the TBCS ppzkSNARK that: + * (1) accepts a non-processed verification key, and + * (2) has strong input consistency. + */ +template +bool tbcs_ppzksnark_verifier_strong_IC(const tbcs_ppzksnark_verification_key &vk, + const tbcs_ppzksnark_primary_input &primary_input, + const tbcs_ppzksnark_proof &proof); + +/** + * Convert a (non-processed) verification key into a processed verification key. + */ +template +tbcs_ppzksnark_processed_verification_key tbcs_ppzksnark_verifier_process_vk(const tbcs_ppzksnark_verification_key &vk); + +/** + * A verifier algorithm for the TBCS ppzkSNARK that: + * (1) accepts a processed verification key, and + * (2) has weak input consistency. + */ +template +bool tbcs_ppzksnark_online_verifier_weak_IC(const tbcs_ppzksnark_processed_verification_key &pvk, + const tbcs_ppzksnark_primary_input &primary_input, + const tbcs_ppzksnark_proof &proof); + +/** + * A verifier algorithm for the TBCS ppzkSNARK that: + * (1) accepts a processed verification key, and + * (2) has strong input consistency. + */ +template +bool tbcs_ppzksnark_online_verifier_strong_IC(const tbcs_ppzksnark_processed_verification_key &pvk, + const tbcs_ppzksnark_primary_input &primary_input, + const tbcs_ppzksnark_proof &proof); + +} // libsnark + +#include "zk_proof_systems/ppzksnark/tbcs_ppzksnark/tbcs_ppzksnark.tcc" + +#endif // TBCS_PPZKSNARK_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/tbcs_ppzksnark/tbcs_ppzksnark.tcc b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/tbcs_ppzksnark/tbcs_ppzksnark.tcc new file mode 100644 index 0000000..bb8030f --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/tbcs_ppzksnark/tbcs_ppzksnark.tcc @@ -0,0 +1,151 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for a ppzkSNARK for TBCS. + + See tbcs_ppzksnark.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef TBCS_PPZKSNARK_TCC_ +#define TBCS_PPZKSNARK_TCC_ + +#include "reductions/tbcs_to_uscs/tbcs_to_uscs.hpp" + +namespace libsnark { + + +template +bool tbcs_ppzksnark_proving_key::operator==(const tbcs_ppzksnark_proving_key &other) const +{ + return (this->circuit == other.circuit && + this->uscs_pk == other.uscs_pk); +} + +template +std::ostream& operator<<(std::ostream &out, const tbcs_ppzksnark_proving_key &pk) +{ + out << pk.circuit << OUTPUT_NEWLINE; + out << pk.uscs_pk << OUTPUT_NEWLINE; + + return out; +} + +template +std::istream& operator>>(std::istream &in, tbcs_ppzksnark_proving_key &pk) +{ + in >> pk.circuit; + consume_OUTPUT_NEWLINE(in); + in >> pk.uscs_pk; + consume_OUTPUT_NEWLINE(in); + + return in; +} + + +template +tbcs_ppzksnark_keypair tbcs_ppzksnark_generator(const tbcs_ppzksnark_circuit &circuit) +{ + typedef Fr FieldT; + + enter_block("Call to tbcs_ppzksnark_generator"); + const uscs_constraint_system uscs_cs = tbcs_to_uscs_instance_map(circuit); + const uscs_ppzksnark_keypair uscs_keypair = uscs_ppzksnark_generator(uscs_cs); + leave_block("Call to tbcs_ppzksnark_generator"); + + return tbcs_ppzksnark_keypair(tbcs_ppzksnark_proving_key(circuit, uscs_keypair.pk), + uscs_keypair.vk); +} + +template +tbcs_ppzksnark_proof tbcs_ppzksnark_prover(const tbcs_ppzksnark_proving_key &pk, + const tbcs_ppzksnark_primary_input &primary_input, + const tbcs_ppzksnark_auxiliary_input &auxiliary_input) +{ + typedef Fr FieldT; + + enter_block("Call to tbcs_ppzksnark_prover"); + const uscs_variable_assignment uscs_va = tbcs_to_uscs_witness_map(pk.circuit, primary_input, auxiliary_input); + const uscs_primary_input uscs_pi = convert_bit_vector_to_field_element_vector(primary_input); + const uscs_auxiliary_input uscs_ai(uscs_va.begin() + primary_input.size(), uscs_va.end()); // TODO: faster to just change bacs_to_r1cs_witness_map into two :( + const uscs_ppzksnark_proof uscs_proof = uscs_ppzksnark_prover(pk.uscs_pk, uscs_pi, uscs_ai); + leave_block("Call to tbcs_ppzksnark_prover"); + + return uscs_proof; +} + +template +tbcs_ppzksnark_processed_verification_key tbcs_ppzksnark_verifier_process_vk(const tbcs_ppzksnark_verification_key &vk) +{ + enter_block("Call to tbcs_ppzksnark_verifier_process_vk"); + const tbcs_ppzksnark_processed_verification_key pvk = uscs_ppzksnark_verifier_process_vk(vk); + leave_block("Call to tbcs_ppzksnark_verifier_process_vk"); + + return pvk; +} + +template +bool tbcs_ppzksnark_verifier_weak_IC(const tbcs_ppzksnark_verification_key &vk, + const tbcs_ppzksnark_primary_input &primary_input, + const tbcs_ppzksnark_proof &proof) +{ + typedef Fr FieldT; + enter_block("Call to tbcs_ppzksnark_verifier_weak_IC"); + const uscs_primary_input uscs_input = convert_bit_vector_to_field_element_vector(primary_input); + const tbcs_ppzksnark_processed_verification_key pvk = tbcs_ppzksnark_verifier_process_vk(vk); + const bool bit = uscs_ppzksnark_online_verifier_weak_IC(pvk, uscs_input, proof); + leave_block("Call to tbcs_ppzksnark_verifier_weak_IC"); + + return bit; +} + +template +bool tbcs_ppzksnark_verifier_strong_IC(const tbcs_ppzksnark_verification_key &vk, + const tbcs_ppzksnark_primary_input &primary_input, + const tbcs_ppzksnark_proof &proof) +{ + typedef Fr FieldT; + enter_block("Call to tbcs_ppzksnark_verifier_strong_IC"); + const tbcs_ppzksnark_processed_verification_key pvk = tbcs_ppzksnark_verifier_process_vk(vk); + const uscs_primary_input uscs_input = convert_bit_vector_to_field_element_vector(primary_input); + const bool bit = uscs_ppzksnark_online_verifier_strong_IC(pvk, uscs_input, proof); + leave_block("Call to tbcs_ppzksnark_verifier_strong_IC"); + + return bit; +} + +template +bool tbcs_ppzksnark_online_verifier_weak_IC(const tbcs_ppzksnark_processed_verification_key &pvk, + const tbcs_ppzksnark_primary_input &primary_input, + const tbcs_ppzksnark_proof &proof) +{ + typedef Fr FieldT; + enter_block("Call to tbcs_ppzksnark_online_verifier_weak_IC"); + const uscs_primary_input uscs_input = convert_bit_vector_to_field_element_vector(primary_input); + const bool bit = uscs_ppzksnark_online_verifier_weak_IC(pvk, uscs_input, proof); + leave_block("Call to tbcs_ppzksnark_online_verifier_weak_IC"); + + return bit; +} + +template +bool tbcs_ppzksnark_online_verifier_strong_IC(const tbcs_ppzksnark_processed_verification_key &pvk, + const tbcs_ppzksnark_primary_input &primary_input, + const tbcs_ppzksnark_proof &proof) +{ + typedef Fr FieldT; + enter_block("Call to tbcs_ppzksnark_online_verifier_strong_IC"); + const uscs_primary_input uscs_input = convert_bit_vector_to_field_element_vector(primary_input); + const bool bit = uscs_ppzksnark_online_verifier_strong_IC(pvk, uscs_input, proof); + leave_block("Call to tbcs_ppzksnark_online_verifier_strong_IC"); + + return bit; +} + +} // libsnark + +#endif // TBCS_PPZKSNARK_TCC_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/tbcs_ppzksnark/tbcs_ppzksnark_params.hpp b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/tbcs_ppzksnark/tbcs_ppzksnark_params.hpp new file mode 100644 index 0000000..4214b24 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/tbcs_ppzksnark/tbcs_ppzksnark_params.hpp @@ -0,0 +1,31 @@ +/** @file + ***************************************************************************** + + Declaration of public-parameter selector for the TBCS ppzkSNARK. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef TBCS_PPZKSNARK_PARAMS_HPP_ +#define TBCS_PPZKSNARK_PARAMS_HPP_ + +#include "relations/circuit_satisfaction_problems/tbcs/tbcs.hpp" + +namespace libsnark { + +/** + * Below are various typedefs aliases (used for uniformity with other proof systems). + */ + +typedef tbcs_circuit tbcs_ppzksnark_circuit; + +typedef tbcs_primary_input tbcs_ppzksnark_primary_input; + +typedef tbcs_auxiliary_input tbcs_ppzksnark_auxiliary_input; + +} // libsnark + +#endif // TBCS_PPZKSNARK_PARAMS_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/tbcs_ppzksnark/tests/test_tbcs_ppzksnark.cpp b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/tbcs_ppzksnark/tests/test_tbcs_ppzksnark.cpp new file mode 100644 index 0000000..22973fe --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/tbcs_ppzksnark/tests/test_tbcs_ppzksnark.cpp @@ -0,0 +1,46 @@ +/** @file + ***************************************************************************** + Test program that exercises the ppzkSNARK (first generator, then + prover, then verifier) on a synthetic TBCS instance. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ +#include +#include + +#include "common/default_types/tbcs_ppzksnark_pp.hpp" +#include "common/profiling.hpp" +#include "relations/circuit_satisfaction_problems/tbcs/examples/tbcs_examples.hpp" +#include "zk_proof_systems/ppzksnark/tbcs_ppzksnark/examples/run_tbcs_ppzksnark.hpp" + +using namespace libsnark; + +template +void test_tbcs_ppzksnark(const size_t primary_input_size, + const size_t auxiliary_input_size, + const size_t num_gates, + const size_t num_outputs) +{ + print_header("(enter) Test TBCS ppzkSNARK"); + + const bool test_serialization = true; + const tbcs_example example = generate_tbcs_example(primary_input_size, auxiliary_input_size, num_gates, num_outputs); +#ifdef DEBUG + example.circuit.print(); +#endif + const bool bit = run_tbcs_ppzksnark(example, test_serialization); + assert(bit); + + print_header("(leave) Test TBCS ppzkSNARK"); +} + +int main() +{ + default_tbcs_ppzksnark_pp::init_public_params(); + start_profiling(); + + test_tbcs_ppzksnark(10, 10, 20, 5); +} diff --git a/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/uscs_ppzksnark/examples/run_uscs_ppzksnark.hpp b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/uscs_ppzksnark/examples/run_uscs_ppzksnark.hpp new file mode 100644 index 0000000..7230620 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/uscs_ppzksnark/examples/run_uscs_ppzksnark.hpp @@ -0,0 +1,35 @@ +/** @file + ***************************************************************************** + + Declaration of functionality that runs the USCS ppzkSNARK for + a given USCS example. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef RUN_USCS_PPZKSNARK_HPP_ +#define RUN_USCS_PPZKSNARK_HPP_ + +#include "relations/constraint_satisfaction_problems/uscs/examples/uscs_examples.hpp" + +namespace libsnark { + +/** + * Runs the ppzkSNARK (generator, prover, and verifier) for a given + * USCS example (specified by a constraint system, input, and witness). + * + * Optionally, also test the serialization routines for keys and proofs. + * (This takes additional time.) + */ +template +bool run_uscs_ppzksnark(const uscs_example > &example, + const bool test_serialization); + +} // libsnark + +#include "zk_proof_systems/ppzksnark/uscs_ppzksnark/examples/run_uscs_ppzksnark.tcc" + +#endif // RUN_USCS_PPZKSNARK_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/uscs_ppzksnark/examples/run_uscs_ppzksnark.tcc b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/uscs_ppzksnark/examples/run_uscs_ppzksnark.tcc new file mode 100644 index 0000000..7a9a045 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/uscs_ppzksnark/examples/run_uscs_ppzksnark.tcc @@ -0,0 +1,87 @@ +/** @file + ***************************************************************************** + + Implementation of functionality that runs the USCS ppzkSNARK for + a given USCS example. + + See run_uscs_ppzksnark.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef RUN_USCS_PPZKSNARK_TCC_ +#define RUN_USCS_PPZKSNARK_TCC_ + +#include "zk_proof_systems/ppzksnark/uscs_ppzksnark/uscs_ppzksnark.hpp" + +#include + +#include "common/profiling.hpp" + +namespace libsnark { + +/** + * The code below provides an example of all stages of running a USCS ppzkSNARK. + * + * Of course, in a real-life scenario, we would have three distinct entities, + * mangled into one in the demonstration below. The three entities are as follows. + * (1) The "generator", which runs the ppzkSNARK generator on input a given + * constraint system CS to create a proving and a verification key for CS. + * (2) The "prover", which runs the ppzkSNARK prover on input the proving key, + * a primary input for CS, and an auxiliary input for CS. + * (3) The "verifier", which runs the ppzkSNARK verifier on input the verification key, + * a primary input for CS, and a proof. + */ +template +bool run_uscs_ppzksnark(const uscs_example > &example, + const bool test_serialization) +{ + enter_block("Call to run_uscs_ppzksnark"); + + print_header("USCS ppzkSNARK Generator"); + uscs_ppzksnark_keypair keypair = uscs_ppzksnark_generator(example.constraint_system); + printf("\n"); print_indent(); print_mem("after generator"); + + print_header("Preprocess verification key"); + uscs_ppzksnark_processed_verification_key pvk = uscs_ppzksnark_verifier_process_vk(keypair.vk); + + if (test_serialization) + { + enter_block("Test serialization of keys"); + keypair.pk = reserialize >(keypair.pk); + keypair.vk = reserialize >(keypair.vk); + pvk = reserialize >(pvk); + leave_block("Test serialization of keys"); + } + + print_header("USCS ppzkSNARK Prover"); + uscs_ppzksnark_proof proof = uscs_ppzksnark_prover(keypair.pk, example.primary_input, example.auxiliary_input); + printf("\n"); print_indent(); print_mem("after prover"); + + if (test_serialization) + { + enter_block("Test serialization of proof"); + proof = reserialize >(proof); + leave_block("Test serialization of proof"); + } + + print_header("USCS ppzkSNARK Verifier"); + bool ans = uscs_ppzksnark_verifier_strong_IC(keypair.vk, example.primary_input, proof); + printf("\n"); print_indent(); print_mem("after verifier"); + printf("* The verification result is: %s\n", (ans ? "PASS" : "FAIL")); + + print_header("USCS ppzkSNARK Online Verifier"); + bool ans2 = uscs_ppzksnark_online_verifier_strong_IC(pvk, example.primary_input, proof); + assert(ans == ans2); + + leave_block("Call to run_uscs_ppzksnark"); + + return ans; +} + +} // libsnark + +#endif // RUN_USCS_PPZKSNARK_TCC_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/uscs_ppzksnark/profiling/profile_uscs_ppzksnark.cpp b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/uscs_ppzksnark/profiling/profile_uscs_ppzksnark.cpp new file mode 100644 index 0000000..0edfec6 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/uscs_ppzksnark/profiling/profile_uscs_ppzksnark.cpp @@ -0,0 +1,65 @@ +/** @file + ***************************************************************************** + Profiling program that exercises the ppzkSNARK (first generator, then prover, + then verifier) on a synthetic USCS instance. + + The command + + $ src/zk_proof_systems/ppzksnark/uscs_ppzksnark/profiling/profile_uscs_ppzksnark 1000 10 Fr + + exercises the ppzkSNARK (first generator, then prover, then verifier) on an USCS instance with 1000 equations and an input consisting of 10 field elements. + + (If you get the error `zmInit ERR:can't protect`, see the discussion [above](#elliptic-curve-choices).) + + The command + + $ src/zk_proof_systems/ppzksnark/uscs_ppzksnark/profiling/profile_uscs_ppzksnark 1000 10 bytes + + does the same but now the input consists of 10 bytes. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include +#include + +#include "common/default_types/uscs_ppzksnark_pp.hpp" +#include "common/profiling.hpp" +#include "common/utils.hpp" +#include "relations/constraint_satisfaction_problems/uscs/examples/uscs_examples.hpp" +#include "zk_proof_systems/ppzksnark/uscs_ppzksnark/examples/run_uscs_ppzksnark.hpp" + +using namespace libsnark; + +int main(int argc, const char * argv[]) +{ + default_uscs_ppzksnark_pp::init_public_params(); + start_profiling(); + + if (argc == 2 && strcmp(argv[1], "-v") == 0) + { + print_compilation_info(); + return 0; + } + + if (argc != 3) + { + printf("usage: %s num_constraints input_size\n", argv[0]); + return 1; + } + + const int num_constraints = atoi(argv[1]); + const int input_size = atoi(argv[2]); + + enter_block("Generate USCS example"); + uscs_example > example = generate_uscs_example_with_field_input >(num_constraints, input_size); + leave_block("Generate USCS example"); + + print_header("(enter) Profile USCS ppzkSNARK"); + const bool test_serialization = true; + run_uscs_ppzksnark(example, test_serialization); + print_header("(leave) Profile USCS ppzkSNARK"); +} diff --git a/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/uscs_ppzksnark/tests/test_uscs_ppzksnark.cpp b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/uscs_ppzksnark/tests/test_uscs_ppzksnark.cpp new file mode 100644 index 0000000..6e8491c --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/uscs_ppzksnark/tests/test_uscs_ppzksnark.cpp @@ -0,0 +1,42 @@ +/** @file + ***************************************************************************** + Test program that exercises the ppzkSNARK (first generator, then + prover, then verifier) on a synthetic USCS instance. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ +#include +#include + +#include "common/default_types/uscs_ppzksnark_pp.hpp" +#include "common/profiling.hpp" +#include "common/utils.hpp" +#include "relations/constraint_satisfaction_problems/uscs/examples/uscs_examples.hpp" +#include "zk_proof_systems/ppzksnark/uscs_ppzksnark/examples/run_uscs_ppzksnark.hpp" + +using namespace libsnark; + +template +void test_uscs_ppzksnark(size_t num_constraints, + size_t input_size) +{ + print_header("(enter) Test USCS ppzkSNARK"); + + const bool test_serialization = true; + uscs_example > example = generate_uscs_example_with_binary_input >(num_constraints, input_size); + const bool bit = run_uscs_ppzksnark(example, test_serialization); + assert(bit); + + print_header("(leave) Test USCS ppzkSNARK"); +} + +int main() +{ + default_uscs_ppzksnark_pp::init_public_params(); + start_profiling(); + + test_uscs_ppzksnark(1000, 100); +} diff --git a/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/uscs_ppzksnark/uscs_ppzksnark.hpp b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/uscs_ppzksnark/uscs_ppzksnark.hpp new file mode 100644 index 0000000..29c53d3 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/uscs_ppzksnark/uscs_ppzksnark.hpp @@ -0,0 +1,428 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for a ppzkSNARK for USCS. + + This includes: + - class for proving key + - class for verification key + - class for processed verification key + - class for key pair (proving key & verification key) + - class for proof + - generator algorithm + - prover algorithm + - verifier algorithm (with strong or weak input consistency) + - online verifier algorithm (with strong or weak input consistency) + + The implementation instantiates the protocol of \[DFGK14], by following + extending, and optimizing the approach described in \[BCTV14]. + + + Acronyms: + + - "ppzkSNARK" = "Pre-Processing Zero-Knowledge Succinct Non-interactive ARgument of Knowledge" + - "USCS" = "Unitary-Square Constraint Systems" + + References: + + \[BCTV14]: + "Succinct Non-Interactive Zero Knowledge for a von Neumann Architecture", + Eli Ben-Sasson, Alessandro Chiesa, Eran Tromer, Madars Virza, + USENIX Security 2014, + + + \[DFGK14]: + "Square Span Programs with Applications to Succinct NIZK Arguments" + George Danezis, Cedric Fournet, Jens Groth, Markulf Kohlweiss, + ASIACRYPT 2014, + + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef USCS_PPZKSNARK_HPP_ +#define USCS_PPZKSNARK_HPP_ + +#include + +#include "algebra/curves/public_params.hpp" +#include "common/data_structures/accumulation_vector.hpp" +#include "algebra/knowledge_commitment/knowledge_commitment.hpp" +#include "relations/constraint_satisfaction_problems/uscs/uscs.hpp" +#include "zk_proof_systems/ppzksnark/uscs_ppzksnark/uscs_ppzksnark_params.hpp" + +namespace libsnark { + +/******************************** Proving key ********************************/ + +template +class uscs_ppzksnark_proving_key; + +template +std::ostream& operator<<(std::ostream &out, const uscs_ppzksnark_proving_key &pk); + +template +std::istream& operator>>(std::istream &in, uscs_ppzksnark_proving_key &pk); + +/** + * A proving key for the USCS ppzkSNARK. + */ +template +class uscs_ppzksnark_proving_key { +public: + G1_vector V_g1_query; + G1_vector alpha_V_g1_query; + G1_vector H_g1_query; + G2_vector V_g2_query; + + uscs_ppzksnark_constraint_system constraint_system; + + uscs_ppzksnark_proving_key() {}; + uscs_ppzksnark_proving_key& operator=(const uscs_ppzksnark_proving_key &other) = default; + uscs_ppzksnark_proving_key(const uscs_ppzksnark_proving_key &other) = default; + uscs_ppzksnark_proving_key(uscs_ppzksnark_proving_key &&other) = default; + uscs_ppzksnark_proving_key(G1_vector &&V_g1_query, + G1_vector &&alpha_V_g1_query, + G1_vector &&H_g1_query, + G2_vector &&V_g2_query, + uscs_ppzksnark_constraint_system &&constraint_system) : + V_g1_query(std::move(V_g1_query)), + alpha_V_g1_query(std::move(alpha_V_g1_query)), + H_g1_query(std::move(H_g1_query)), + V_g2_query(std::move(V_g2_query)), + constraint_system(std::move(constraint_system)) + {}; + + size_t G1_size() const + { + return V_g1_query.size() + alpha_V_g1_query.size() + H_g1_query.size(); + } + + size_t G2_size() const + { + return V_g2_query.size(); + } + + size_t G1_sparse_size() const + { + return G1_size(); + } + + size_t G2_sparse_size() const + { + return G2_size(); + } + + size_t size_in_bits() const + { + return G1::size_in_bits() * G1_size() + G2::size_in_bits() * G2_size(); + } + + void print_size() const + { + print_indent(); printf("* G1 elements in PK: %zu\n", this->G1_size()); + print_indent(); printf("* Non-zero G1 elements in PK: %zu\n", this->G1_sparse_size()); + print_indent(); printf("* G2 elements in PK: %zu\n", this->G2_size()); + print_indent(); printf("* Non-zero G2 elements in PK: %zu\n", this->G2_sparse_size()); + print_indent(); printf("* PK size in bits: %zu\n", this->size_in_bits()); + } + + bool operator==(const uscs_ppzksnark_proving_key &other) const; + friend std::ostream& operator<< (std::ostream &out, const uscs_ppzksnark_proving_key &pk); + friend std::istream& operator>> (std::istream &in, uscs_ppzksnark_proving_key &pk); +}; + + +/******************************* Verification key ****************************/ + +template +class uscs_ppzksnark_verification_key; + +template +std::ostream& operator<<(std::ostream &out, const uscs_ppzksnark_verification_key &vk); + +template +std::istream& operator>>(std::istream &in, uscs_ppzksnark_verification_key &vk); + +/** + * A verification key for the USCS ppzkSNARK. + */ +template +class uscs_ppzksnark_verification_key { +public: + G2 tilde_g2; + G2 alpha_tilde_g2; + G2 Z_g2; + + accumulation_vector > encoded_IC_query; + + uscs_ppzksnark_verification_key() = default; + uscs_ppzksnark_verification_key(const G2 &tilde_g2, + const G2 &alpha_tilde_g2, + const G2 &Z_g2, + const accumulation_vector > &eIC) : + tilde_g2(tilde_g2), + alpha_tilde_g2(alpha_tilde_g2), + Z_g2(Z_g2), + encoded_IC_query(eIC) + {}; + + size_t G1_size() const + { + return encoded_IC_query.size(); + } + + size_t G2_size() const + { + return 3; + } + + size_t size_in_bits() const + { + return encoded_IC_query.size_in_bits() + 3 * G2::size_in_bits(); + } + + void print_size() const + { + print_indent(); printf("* G1 elements in VK: %zu\n", this->G1_size()); + print_indent(); printf("* G2 elements in VK: %zu\n", this->G2_size()); + print_indent(); printf("* VK size in bits: %zu\n", this->size_in_bits()); + } + + bool operator==(const uscs_ppzksnark_verification_key &other) const; + friend std::ostream& operator<< (std::ostream &out, const uscs_ppzksnark_verification_key &vk); + friend std::istream& operator>> (std::istream &in, uscs_ppzksnark_verification_key &vk); + + static uscs_ppzksnark_verification_key dummy_verification_key(const size_t input_size); +}; + + +/************************ Processed verification key *************************/ + +template +class uscs_ppzksnark_processed_verification_key; + +template +std::ostream& operator<<(std::ostream &out, const uscs_ppzksnark_processed_verification_key &pvk); + +template +std::istream& operator>>(std::istream &in, uscs_ppzksnark_processed_verification_key &pvk); + +/** + * A processed verification key for the USCS ppzkSNARK. + * + * Compared to a (non-processed) verification key, a processed verification key + * contains a small constant amount of additional pre-computed information that + * enables a faster verification time. + */ +template +class uscs_ppzksnark_processed_verification_key { +public: + G1_precomp pp_G1_one_precomp; + G2_precomp pp_G2_one_precomp; + G2_precomp vk_tilde_g2_precomp; + G2_precomp vk_alpha_tilde_g2_precomp; + G2_precomp vk_Z_g2_precomp; + GT pairing_of_g1_and_g2; + + accumulation_vector > encoded_IC_query; + + bool operator==(const uscs_ppzksnark_processed_verification_key &other) const; + friend std::ostream& operator<< (std::ostream &out, const uscs_ppzksnark_processed_verification_key &pvk); + friend std::istream& operator>> (std::istream &in, uscs_ppzksnark_processed_verification_key &pvk); +}; + + +/********************************** Key pair *********************************/ + +/** + * A key pair for the USCS ppzkSNARK, which consists of a proving key and a verification key. + */ +template +class uscs_ppzksnark_keypair { +public: + uscs_ppzksnark_proving_key pk; + uscs_ppzksnark_verification_key vk; + + uscs_ppzksnark_keypair() {}; + uscs_ppzksnark_keypair(uscs_ppzksnark_proving_key &&pk, + uscs_ppzksnark_verification_key &&vk) : + pk(std::move(pk)), + vk(std::move(vk)) + {} + + uscs_ppzksnark_keypair(uscs_ppzksnark_keypair &&other) = default; +}; + + +/*********************************** Proof ***********************************/ + +template +class uscs_ppzksnark_proof; + +template +std::ostream& operator<<(std::ostream &out, const uscs_ppzksnark_proof &proof); + +template +std::istream& operator>>(std::istream &in, uscs_ppzksnark_proof &proof); + +/** + * A proof for the USCS ppzkSNARK. + * + * While the proof has a structure, externally one merely opaquely produces, + * seralizes/deserializes, and verifies proofs. We only expose some information + * about the structure for statistics purposes. + */ +template +class uscs_ppzksnark_proof { +public: + G1 V_g1; + G1 alpha_V_g1; + G1 H_g1; + G2 V_g2; + + uscs_ppzksnark_proof() + { + // invalid proof with valid curve points + this->V_g1 = G1 ::one(); + this->alpha_V_g1 = G1 ::one(); + this->H_g1 = G1 ::one(); + this->V_g2 = G2 ::one(); + } + uscs_ppzksnark_proof(G1 &&V_g1, + G1 &&alpha_V_g1, + G1 &&H_g1, + G2 &&V_g2) : + V_g1(std::move(V_g1)), + alpha_V_g1(std::move(alpha_V_g1)), + H_g1(std::move(H_g1)), + V_g2(std::move(V_g2)) + {}; + + size_t G1_size() const + { + return 3; + } + + size_t G2_size() const + { + return 1; + } + + size_t size_in_bits() const + { + return G1_size() * G1::size_in_bits() + G2_size() * G2::size_in_bits(); + } + + void print_size() const + { + print_indent(); printf("* G1 elements in proof: %zu\n", this->G1_size()); + print_indent(); printf("* G2 elements in proof: %zu\n", this->G2_size()); + print_indent(); printf("* Proof size in bits: %zu\n", this->size_in_bits()); + } + + bool is_well_formed() const + { + return (V_g1.is_well_formed() && + alpha_V_g1.is_well_formed() && + H_g1.is_well_formed() && + V_g2.is_well_formed()); + } + + bool operator==(const uscs_ppzksnark_proof &other) const; + friend std::ostream& operator<< (std::ostream &out, const uscs_ppzksnark_proof &proof); + friend std::istream& operator>> (std::istream &in, uscs_ppzksnark_proof &proof); +}; + + +/***************************** Main algorithms *******************************/ + +/** + * A generator algorithm for the USCS ppzkSNARK. + * + * Given a USCS constraint system CS, this algorithm produces proving and verification keys for CS. + */ +template +uscs_ppzksnark_keypair uscs_ppzksnark_generator(const uscs_ppzksnark_constraint_system &cs); + +/** + * A prover algorithm for the USCS ppzkSNARK. + * + * Given a USCS primary input X and a USCS auxiliary input Y, this algorithm + * produces a proof (of knowledge) that attests to the following statement: + * ``there exists Y such that CS(X,Y)=0''. + * Above, CS is the USCS constraint system that was given as input to the generator algorithm. + */ +template +uscs_ppzksnark_proof uscs_ppzksnark_prover(const uscs_ppzksnark_proving_key &pk, + const uscs_ppzksnark_primary_input &primary_input, + const uscs_ppzksnark_auxiliary_input &auxiliary_input); + +/* + Below are four variants of verifier algorithm for the USCS ppzkSNARK. + + These are the four cases that arise from the following two choices: + + (1) The verifier accepts a (non-processed) verification key or, instead, a processed verification key. + In the latter case, we call the algorithm an "online verifier". + + (2) The verifier checks for "weak" input consistency or, instead, "strong" input consistency. + Strong input consistency requires that |primary_input| = CS.num_inputs, whereas + weak input consistency requires that |primary_input| <= CS.num_inputs (and + the primary input is implicitly padded with zeros up to length CS.num_inputs). + */ + +/** + * A verifier algorithm for the USCS ppzkSNARK that: + * (1) accepts a non-processed verification key, and + * (2) has weak input consistency. + */ +template +bool uscs_ppzksnark_verifier_weak_IC(const uscs_ppzksnark_verification_key &vk, + const uscs_ppzksnark_primary_input &primary_input, + const uscs_ppzksnark_proof &proof); + +/** + * A verifier algorithm for the USCS ppzkSNARK that: + * (1) accepts a non-processed verification key, and + * (2) has strong input consistency. + */ +template +bool uscs_ppzksnark_verifier_strong_IC(const uscs_ppzksnark_verification_key &vk, + const uscs_ppzksnark_primary_input &primary_input, + const uscs_ppzksnark_proof &proof); + +/** + * Convert a (non-processed) verification key into a processed verification key. + */ +template +uscs_ppzksnark_processed_verification_key uscs_ppzksnark_verifier_process_vk(const uscs_ppzksnark_verification_key &vk); + +/** + * A verifier algorithm for the USCS ppzkSNARK that: + * (1) accepts a processed verification key, and + * (2) has weak input consistency. + */ +template +bool uscs_ppzksnark_online_verifier_weak_IC(const uscs_ppzksnark_processed_verification_key &pvk, + const uscs_ppzksnark_primary_input &primary_input, + const uscs_ppzksnark_proof &proof); + +/** + * A verifier algorithm for the USCS ppzkSNARK that: + * (1) accepts a processed verification key, and + * (2) has strong input consistency. + */ +template +bool uscs_ppzksnark_online_verifier_strong_IC(const uscs_ppzksnark_processed_verification_key &pvk, + const uscs_ppzksnark_primary_input &primary_input, + const uscs_ppzksnark_proof &proof); + +} // libsnark + +#include "zk_proof_systems/ppzksnark/uscs_ppzksnark/uscs_ppzksnark.tcc" + +#endif // USCS_PPZKSNARK_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/uscs_ppzksnark/uscs_ppzksnark.tcc b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/uscs_ppzksnark/uscs_ppzksnark.tcc new file mode 100644 index 0000000..4d47b40 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/uscs_ppzksnark/uscs_ppzksnark.tcc @@ -0,0 +1,553 @@ +/** @file + ***************************************************************************** + Implementation of interfaces for a ppzkSNARK for USCS. + + See uscs_ppzksnark.hpp . + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef USCS_PPZKSNARK_TCC_ +#define USCS_PPZKSNARK_TCC_ + +#include +#include +#include +#include +#include + +#include "reductions/uscs_to_ssp/uscs_to_ssp.hpp" +#include "common/profiling.hpp" +#include "common/utils.hpp" +#include "algebra/scalar_multiplication/multiexp.hpp" +#include "relations/arithmetic_programs/ssp/ssp.hpp" + +namespace libsnark { + +template +bool uscs_ppzksnark_proving_key::operator==(const uscs_ppzksnark_proving_key &other) const +{ + return (this->V_g1_query == other.V_g1_query && + this->alpha_V_g1_query == other.alpha_V_g1_query && + this->H_g1_query == other.H_g1_query && + this->V_g2_query == other.V_g2_query && + this->constraint_system == other.constraint_system); +} + +template +std::ostream& operator<<(std::ostream &out, const uscs_ppzksnark_proving_key &pk) +{ + out << pk.V_g1_query; + out << pk.alpha_V_g1_query; + out << pk.H_g1_query; + out << pk.V_g2_query; + out << pk.constraint_system; + + return out; +} + +template +std::istream& operator>>(std::istream &in, uscs_ppzksnark_proving_key &pk) +{ + in >> pk.V_g1_query; + in >> pk.alpha_V_g1_query; + in >> pk.H_g1_query; + in >> pk.V_g2_query; + in >> pk.constraint_system; + + return in; +} + +template +bool uscs_ppzksnark_verification_key::operator==(const uscs_ppzksnark_verification_key &other) const +{ + return (this->tilde_g2 == other.tilde_g2 && + this->alpha_tilde_g2 == other.alpha_tilde_g2 && + this->Z_g2 == other.Z_g2 && + this->encoded_IC_query == other.encoded_IC_query); +} + +template +std::ostream& operator<<(std::ostream &out, const uscs_ppzksnark_verification_key &vk) +{ + out << vk.tilde_g2 << OUTPUT_NEWLINE; + out << vk.alpha_tilde_g2 << OUTPUT_NEWLINE; + out << vk.Z_g2 << OUTPUT_NEWLINE; + out << vk.encoded_IC_query << OUTPUT_NEWLINE; + + return out; +} + +template +std::istream& operator>>(std::istream &in, uscs_ppzksnark_verification_key &vk) +{ + in >> vk.tilde_g2; + consume_OUTPUT_NEWLINE(in); + in >> vk.alpha_tilde_g2; + consume_OUTPUT_NEWLINE(in); + in >> vk.Z_g2; + consume_OUTPUT_NEWLINE(in); + in >> vk.encoded_IC_query; + consume_OUTPUT_NEWLINE(in); + + return in; +} + +template +bool uscs_ppzksnark_processed_verification_key::operator==(const uscs_ppzksnark_processed_verification_key &other) const +{ + return (this->pp_G1_one_precomp == other.pp_G1_one_precomp && + this->pp_G2_one_precomp == other.pp_G2_one_precomp && + this->vk_tilde_g2_precomp == other.vk_tilde_g2_precomp && + this->vk_alpha_tilde_g2_precomp == other.vk_alpha_tilde_g2_precomp && + this->vk_Z_g2_precomp == other.vk_Z_g2_precomp && + this->pairing_of_g1_and_g2 == other.pairing_of_g1_and_g2 && + this->encoded_IC_query == other.encoded_IC_query); +} + +template +std::ostream& operator<<(std::ostream &out, const uscs_ppzksnark_processed_verification_key &pvk) +{ + out << pvk.pp_G1_one_precomp << OUTPUT_NEWLINE; + out << pvk.pp_G2_one_precomp << OUTPUT_NEWLINE; + out << pvk.vk_tilde_g2_precomp << OUTPUT_NEWLINE; + out << pvk.vk_alpha_tilde_g2_precomp << OUTPUT_NEWLINE; + out << pvk.vk_Z_g2_precomp << OUTPUT_NEWLINE; + out << pvk.pairing_of_g1_and_g2 << OUTPUT_NEWLINE; + out << pvk.encoded_IC_query << OUTPUT_NEWLINE; + + return out; +} + +template +std::istream& operator>>(std::istream &in, uscs_ppzksnark_processed_verification_key &pvk) +{ + in >> pvk.pp_G1_one_precomp; + consume_OUTPUT_NEWLINE(in); + in >> pvk.pp_G2_one_precomp; + consume_OUTPUT_NEWLINE(in); + in >> pvk.vk_tilde_g2_precomp; + consume_OUTPUT_NEWLINE(in); + in >> pvk.vk_alpha_tilde_g2_precomp; + consume_OUTPUT_NEWLINE(in); + in >> pvk.vk_Z_g2_precomp; + consume_OUTPUT_NEWLINE(in); + in >> pvk.pairing_of_g1_and_g2; + consume_OUTPUT_NEWLINE(in); + in >> pvk.encoded_IC_query; + consume_OUTPUT_NEWLINE(in); + + return in; +} + +template +bool uscs_ppzksnark_proof::operator==(const uscs_ppzksnark_proof &other) const +{ + return (this->V_g1 == other.V_g1 && + this->alpha_V_g1 == other.alpha_V_g1 && + this->H_g1 == other.H_g1 && + this->V_g2 == other.V_g2); +} + +template +std::ostream& operator<<(std::ostream &out, const uscs_ppzksnark_proof &proof) +{ + out << proof.V_g1 << OUTPUT_NEWLINE; + out << proof.alpha_V_g1 << OUTPUT_NEWLINE; + out << proof.H_g1 << OUTPUT_NEWLINE; + out << proof.V_g2 << OUTPUT_NEWLINE; + + return out; +} + +template +std::istream& operator>>(std::istream &in, uscs_ppzksnark_proof &proof) +{ + in >> proof.V_g1; + consume_OUTPUT_NEWLINE(in); + in >> proof.alpha_V_g1; + consume_OUTPUT_NEWLINE(in); + in >> proof.H_g1; + consume_OUTPUT_NEWLINE(in); + in >> proof.V_g2; + consume_OUTPUT_NEWLINE(in); + + return in; +} + +template +uscs_ppzksnark_verification_key uscs_ppzksnark_verification_key::dummy_verification_key(const size_t input_size) +{ + uscs_ppzksnark_verification_key result; + result.tilde_g2 = Fr::random_element() * G2::one(); + result.alpha_tilde_g2 = Fr::random_element() * G2::one(); + result.Z_g2 = Fr::random_element() * G2::one(); + + G1 base = Fr::random_element() * G1::one(); + G1_vector v; + for (size_t i = 0; i < input_size; ++i) + { + v.emplace_back(Fr::random_element() * G1::one()); + } + + result.encoded_IC_query = accumulation_vector >(v); + + return result; +} + +template +uscs_ppzksnark_keypair uscs_ppzksnark_generator(const uscs_ppzksnark_constraint_system &cs) +{ + enter_block("Call to uscs_ppzksnark_generator"); + + /* draw random element at which the SSP is evaluated */ + + const Fr t = Fr::random_element(); + + /* perform USCS-to-SSP reduction */ + + ssp_instance_evaluation > ssp_inst = uscs_to_ssp_instance_map_with_evaluation(cs, t); + + print_indent(); printf("* SSP number of variables: %zu\n", ssp_inst.num_variables()); + print_indent(); printf("* SSP pre degree: %zu\n", cs.num_constraints()); + print_indent(); printf("* SSP degree: %zu\n", ssp_inst.degree()); + print_indent(); printf("* SSP number of input variables: %zu\n", ssp_inst.num_inputs()); + + /* construct various tables of FieldT elements */ + + Fr_vector Vt_table = std::move(ssp_inst.Vt); // ssp_inst.Vt is now in unspecified state, but we do not use it later + Fr_vector Ht_table = std::move(ssp_inst.Ht); // ssp_inst.Ht is now in unspecified state, but we do not use it later + + Vt_table.emplace_back(ssp_inst.Zt); + + Fr_vector Xt_table = Fr_vector(Vt_table.begin(), Vt_table.begin() + ssp_inst.num_inputs() + 1); + Fr_vector Vt_table_minus_Xt_table = Fr_vector(Vt_table.begin() + ssp_inst.num_inputs() + 1, Vt_table.end()); + + /* sanity checks */ + + assert(Vt_table.size() == ssp_inst.num_variables() + 2); + printf("Ht_table.size() = %zu, ssp_inst.degree() + 1 = %zu\n", Ht_table.size(), ssp_inst.degree() + 1); + assert(Ht_table.size() == ssp_inst.degree() + 1); + assert(Xt_table.size() == ssp_inst.num_inputs() + 1); + assert(Vt_table_minus_Xt_table.size() == ssp_inst.num_variables() + 2 - ssp_inst.num_inputs() - 1); + for (size_t i = 0; i < ssp_inst.num_inputs()+1; ++i) + { + assert(!Xt_table[i].is_zero()); + } + + const Fr alpha = Fr::random_element(); + + enter_block("Generate USCS proving key"); + + const size_t g1_exp_count = Vt_table.size() + Vt_table_minus_Xt_table.size() + Ht_table.size(); + const size_t g2_exp_count = Vt_table_minus_Xt_table.size(); + + size_t g1_window = get_exp_window_size >(g1_exp_count); + size_t g2_window = get_exp_window_size >(g2_exp_count); + + print_indent(); printf("* G1 window: %zu\n", g1_window); + print_indent(); printf("* G2 window: %zu\n", g2_window); + + enter_block("Generating G1 multiexp table"); + window_table > g1_table = get_window_table(Fr::size_in_bits(), g1_window, G1::one()); + leave_block("Generating G1 multiexp table"); + + enter_block("Generating G2 multiexp table"); + window_table > g2_table = get_window_table(Fr::size_in_bits(), g2_window, G2::one()); + leave_block("Generating G2 multiexp table"); + + enter_block("Generate proof components"); + + enter_block("Compute the query for V_g1", false); + G1_vector V_g1_query = batch_exp(Fr::size_in_bits(), g1_window, g1_table, Vt_table_minus_Xt_table); + leave_block("Compute the query for V_g1", false); + + enter_block("Compute the query for alpha_V_g1", false); + G1_vector alpha_V_g1_query = batch_exp_with_coeff(Fr::size_in_bits(), g1_window, g1_table, alpha, Vt_table_minus_Xt_table); + leave_block("Compute the query for alpha_V_g1", false); + + enter_block("Compute the query for H_g1", false); + G1_vector H_g1_query = batch_exp(Fr::size_in_bits(), g1_window, g1_table, Ht_table); + leave_block("Compute the query for H_g1", false); + + enter_block("Compute the query for V_g2", false); + G2_vector V_g2_query = batch_exp(Fr::size_in_bits(), g2_window, g2_table, Vt_table); + leave_block("Compute the query for V_g2", false); + + leave_block("Generate proof components"); + + leave_block("Generate USCS proving key"); + + enter_block("Generate USCS verification key"); + + const Fr tilde = Fr::random_element(); + G2 tilde_g2 = tilde * G2::one(); + G2 alpha_tilde_g2 = (alpha * tilde) * G2::one(); + G2 Z_g2 = ssp_inst.Zt * G2::one(); + + enter_block("Encode IC query for USCS verification key"); + G1 encoded_IC_base = Xt_table[0] * G1::one(); + G1_vector encoded_IC_values = batch_exp(Fr::size_in_bits(), g1_window, g1_table, Fr_vector(Xt_table.begin() + 1, Xt_table.end())); + leave_block("Encode IC query for USCS verification key"); + + leave_block("Generate USCS verification key"); + + leave_block("Call to uscs_ppzksnark_generator"); + + accumulation_vector > encoded_IC_query(std::move(encoded_IC_base), std::move(encoded_IC_values)); + + uscs_ppzksnark_verification_key vk = uscs_ppzksnark_verification_key(tilde_g2, + alpha_tilde_g2, + Z_g2, + encoded_IC_query); + + uscs_ppzksnark_constraint_system cs_copy = cs; + uscs_ppzksnark_proving_key pk = uscs_ppzksnark_proving_key(std::move(V_g1_query), + std::move(alpha_V_g1_query), + std::move(H_g1_query), + std::move(V_g2_query), + std::move(cs_copy)); + + pk.print_size(); + vk.print_size(); + + return uscs_ppzksnark_keypair(std::move(pk), std::move(vk)); +} + +template +uscs_ppzksnark_proof uscs_ppzksnark_prover(const uscs_ppzksnark_proving_key &pk, + const uscs_ppzksnark_primary_input &primary_input, + const uscs_ppzksnark_auxiliary_input &auxiliary_input) +{ + enter_block("Call to uscs_ppzksnark_prover"); + + const Fr d = Fr::random_element(); + + enter_block("Compute the polynomial H"); + const ssp_witness > ssp_wit = uscs_to_ssp_witness_map(pk.constraint_system, primary_input, auxiliary_input, d); + leave_block("Compute the polynomial H"); + + /* sanity checks */ + assert(pk.constraint_system.is_satisfied(primary_input, auxiliary_input)); + assert(pk.V_g1_query.size() == ssp_wit.num_variables() + 2 - ssp_wit.num_inputs() - 1); + assert(pk.alpha_V_g1_query.size() == ssp_wit.num_variables() + 2 - ssp_wit.num_inputs() - 1); + assert(pk.H_g1_query.size() == ssp_wit.degree() + 1); + assert(pk.V_g2_query.size() == ssp_wit.num_variables() + 2); + +#ifdef DEBUG + const Fr t = Fr::random_element(); + ssp_instance_evaluation > ssp_inst = uscs_to_ssp_instance_map_with_evaluation(pk.constraint_system, t); + assert(ssp_inst.is_satisfied(ssp_wit)); +#endif + + G1 V_g1 = ssp_wit.d*pk.V_g1_query[pk.V_g1_query.size()-1]; + G1 alpha_V_g1 = ssp_wit.d*pk.alpha_V_g1_query[pk.alpha_V_g1_query.size()-1]; + G1 H_g1 = G1::zero(); + G2 V_g2 = pk.V_g2_query[0]+ssp_wit.d*pk.V_g2_query[pk.V_g2_query.size()-1]; + +#ifdef MULTICORE + const size_t chunks = omp_get_max_threads(); // to override, set OMP_NUM_THREADS env var or call omp_set_num_threads() +#else + const size_t chunks = 1; +#endif + + // MAYBE LATER: do queries 1,2,4 at once for slightly better speed + + enter_block("Compute the proof"); + + enter_block("Compute V_g1, the 1st component of the proof", false); + V_g1 = V_g1 + multi_exp_with_mixed_addition, Fr >(pk.V_g1_query.begin(), pk.V_g1_query.begin()+(ssp_wit.num_variables()-ssp_wit.num_inputs()), + ssp_wit.coefficients_for_Vs.begin()+ssp_wit.num_inputs(), ssp_wit.coefficients_for_Vs.begin()+ssp_wit.num_variables(), + chunks, + true); + leave_block("Compute V_g1, the 1st component of the proof", false); + + enter_block("Compute alpha_V_g1, the 2nd component of the proof", false); + alpha_V_g1 = alpha_V_g1 + multi_exp_with_mixed_addition, Fr >(pk.alpha_V_g1_query.begin(), pk.alpha_V_g1_query.begin()+(ssp_wit.num_variables()-ssp_wit.num_inputs()), + ssp_wit.coefficients_for_Vs.begin()+ssp_wit.num_inputs(), ssp_wit.coefficients_for_Vs.begin()+ssp_wit.num_variables(), + chunks, + true); + leave_block("Compute alpha_V_g1, the 2nd component of the proof", false); + + enter_block("Compute H_g1, the 3rd component of the proof", false); + H_g1 = H_g1 + multi_exp, Fr >(pk.H_g1_query.begin(), pk.H_g1_query.begin()+ssp_wit.degree()+1, + ssp_wit.coefficients_for_H.begin(), ssp_wit.coefficients_for_H.begin()+ssp_wit.degree()+1, + chunks, + true); + leave_block("Compute H_g1, the 3rd component of the proof", false); + + enter_block("Compute V_g2, the 4th component of the proof", false); + V_g2 = V_g2 + multi_exp, Fr >(pk.V_g2_query.begin()+1, pk.V_g2_query.begin()+ssp_wit.num_variables()+1, + ssp_wit.coefficients_for_Vs.begin(), ssp_wit.coefficients_for_Vs.begin()+ssp_wit.num_variables(), + chunks, + true); + leave_block("Compute V_g2, the 4th component of the proof", false); + + leave_block("Compute the proof"); + + leave_block("Call to uscs_ppzksnark_prover"); + + uscs_ppzksnark_proof proof = uscs_ppzksnark_proof(std::move(V_g1), std::move(alpha_V_g1), std::move(H_g1), std::move(V_g2)); + + proof.print_size(); + + return proof; +} + +template +uscs_ppzksnark_processed_verification_key uscs_ppzksnark_verifier_process_vk(const uscs_ppzksnark_verification_key &vk) +{ + enter_block("Call to uscs_ppzksnark_verifier_process_vk"); + + uscs_ppzksnark_processed_verification_key pvk; + + pvk.pp_G1_one_precomp = ppT::precompute_G1(G1::one()); + pvk.pp_G2_one_precomp = ppT::precompute_G2(G2::one()); + + pvk.vk_tilde_g2_precomp = ppT::precompute_G2(vk.tilde_g2); + pvk.vk_alpha_tilde_g2_precomp = ppT::precompute_G2(vk.alpha_tilde_g2); + pvk.vk_Z_g2_precomp = ppT::precompute_G2(vk.Z_g2); + + pvk.pairing_of_g1_and_g2 = ppT::miller_loop(pvk.pp_G1_one_precomp,pvk.pp_G2_one_precomp); + + pvk.encoded_IC_query = vk.encoded_IC_query; + + leave_block("Call to uscs_ppzksnark_verifier_process_vk"); + + return pvk; +} + +template +bool uscs_ppzksnark_online_verifier_weak_IC(const uscs_ppzksnark_processed_verification_key &pvk, + const uscs_ppzksnark_primary_input &primary_input, + const uscs_ppzksnark_proof &proof) +{ + enter_block("Call to uscs_ppzksnark_online_verifier_weak_IC"); + assert(pvk.encoded_IC_query.domain_size() >= primary_input.size()); + + enter_block("Compute input-dependent part of V"); + const accumulation_vector > accumulated_IC = pvk.encoded_IC_query.template accumulate_chunk >(primary_input.begin(), primary_input.end(), 0); + assert(accumulated_IC.is_fully_accumulated()); + const G1 &acc = accumulated_IC.first; + leave_block("Compute input-dependent part of V"); + + bool result = true; + + enter_block("Check if the proof is well-formed"); + if (!proof.is_well_formed()) + { + if (!inhibit_profiling_info) + { + print_indent(); printf("At least one of the proof components is not well-formed.\n"); + } + result = false; + } + leave_block("Check if the proof is well-formed"); + + enter_block("Online pairing computations"); + + enter_block("Check knowledge commitment for V is valid"); + G1_precomp proof_V_g1_with_acc_precomp = ppT::precompute_G1(proof.V_g1 + acc); + G2_precomp proof_V_g2_precomp = ppT::precompute_G2(proof.V_g2); + Fqk V_1 = ppT::miller_loop(proof_V_g1_with_acc_precomp, pvk.pp_G2_one_precomp); + Fqk V_2 = ppT::miller_loop(pvk.pp_G1_one_precomp, proof_V_g2_precomp); + GT V = ppT::final_exponentiation(V_1 * V_2.unitary_inverse()); + if (V != GT::one()) + { + if (!inhibit_profiling_info) + { + print_indent(); printf("Knowledge commitment for V invalid.\n"); + } + result = false; + } + leave_block("Check knowledge commitment for V is valid"); + + enter_block("Check SSP divisibility"); // i.e., check that V^2=H*Z+1 + G1_precomp proof_H_g1_precomp = ppT::precompute_G1(proof.H_g1); + Fqk SSP_1 = ppT::miller_loop(proof_V_g1_with_acc_precomp, proof_V_g2_precomp); + Fqk SSP_2 = ppT::miller_loop(proof_H_g1_precomp, pvk.vk_Z_g2_precomp); + GT SSP = ppT::final_exponentiation(SSP_1.unitary_inverse() * SSP_2 * pvk.pairing_of_g1_and_g2); + if (SSP != GT::one()) + { + if (!inhibit_profiling_info) + { + print_indent(); printf("SSP divisibility check failed.\n"); + } + result = false; + } + leave_block("Check SSP divisibility"); + + enter_block("Check same coefficients were used"); + G1_precomp proof_V_g1_precomp = ppT::precompute_G1(proof.V_g1); + G1_precomp proof_alpha_V_g1_precomp = ppT::precompute_G1(proof.alpha_V_g1); + Fqk alpha_V_1 = ppT::miller_loop(proof_V_g1_precomp, pvk.vk_alpha_tilde_g2_precomp); + Fqk alpha_V_2 = ppT::miller_loop(proof_alpha_V_g1_precomp, pvk.vk_tilde_g2_precomp); + GT alpha_V = ppT::final_exponentiation(alpha_V_1 * alpha_V_2.unitary_inverse()); + if (alpha_V != GT::one()) + { + if (!inhibit_profiling_info) + { + print_indent(); printf("Same-coefficient check failed.\n"); + } + result = false; + } + leave_block("Check same coefficients were used"); + + leave_block("Online pairing computations"); + + leave_block("Call to uscs_ppzksnark_online_verifier_weak_IC"); + + return result; +} + +template +bool uscs_ppzksnark_verifier_weak_IC(const uscs_ppzksnark_verification_key &vk, + const uscs_ppzksnark_primary_input &primary_input, + const uscs_ppzksnark_proof &proof) +{ + enter_block("Call to uscs_ppzksnark_verifier_weak_IC"); + uscs_ppzksnark_processed_verification_key pvk = uscs_ppzksnark_verifier_process_vk(vk); + bool result = uscs_ppzksnark_online_verifier_weak_IC(pvk, primary_input, proof); + leave_block("Call to uscs_ppzksnark_verifier_weak_IC"); + return result; +} + +template +bool uscs_ppzksnark_online_verifier_strong_IC(const uscs_ppzksnark_processed_verification_key &pvk, + const uscs_ppzksnark_primary_input &primary_input, + const uscs_ppzksnark_proof &proof) +{ + bool result = true; + enter_block("Call to uscs_ppzksnark_online_verifier_strong_IC"); + + if (pvk.encoded_IC_query.domain_size() != primary_input.size()) + { + print_indent(); printf("Input length differs from expected (got %zu, expected %zu).\n", primary_input.size(), pvk.encoded_IC_query.domain_size()); + result = false; + } + else + { + result = uscs_ppzksnark_online_verifier_weak_IC(pvk, primary_input, proof); + } + + leave_block("Call to uscs_ppzksnark_online_verifier_strong_IC"); + return result; +} + +template +bool uscs_ppzksnark_verifier_strong_IC(const uscs_ppzksnark_verification_key &vk, + const uscs_ppzksnark_primary_input &primary_input, + const uscs_ppzksnark_proof &proof) +{ + enter_block("Call to uscs_ppzksnark_verifier_strong_IC"); + uscs_ppzksnark_processed_verification_key pvk = uscs_ppzksnark_verifier_process_vk(vk); + bool result = uscs_ppzksnark_online_verifier_strong_IC(pvk, primary_input, proof); + leave_block("Call to uscs_ppzksnark_verifier_strong_IC"); + return result; +} + +} // libsnark + +#endif // USCS_PPZKSNARK_TCC_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/uscs_ppzksnark/uscs_ppzksnark_params.hpp b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/uscs_ppzksnark/uscs_ppzksnark_params.hpp new file mode 100644 index 0000000..8cebb5e --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/ppzksnark/uscs_ppzksnark/uscs_ppzksnark_params.hpp @@ -0,0 +1,34 @@ +/** @file + ***************************************************************************** + + Declaration of public-parameter selector for the USCS ppzkSNARK. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef USCS_PPZKSNARK_PARAMS_HPP_ +#define USCS_PPZKSNARK_PARAMS_HPP_ + +#include "relations/constraint_satisfaction_problems/uscs/uscs.hpp" + +namespace libsnark { + +/** + * Below are various template aliases (used for convenience). + */ + +template +using uscs_ppzksnark_constraint_system = uscs_constraint_system >; + +template +using uscs_ppzksnark_primary_input = uscs_primary_input >; + +template +using uscs_ppzksnark_auxiliary_input = uscs_auxiliary_input >; + +} // libsnark + +#endif // USCS_PPZKSNARK_PARAMS_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/zksnark/ram_zksnark/examples/run_ram_zksnark.hpp b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/zksnark/ram_zksnark/examples/run_ram_zksnark.hpp new file mode 100644 index 0000000..db1a34c --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/zksnark/ram_zksnark/examples/run_ram_zksnark.hpp @@ -0,0 +1,36 @@ +/** @file + ***************************************************************************** + + Declaration of functionality that runs the RAM zkSNARK for + a given RAM example. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef RUN_RAM_ZKSNARK_HPP_ +#define RUN_RAM_ZKSNARK_HPP_ + +#include "relations/ram_computations/rams/examples/ram_examples.hpp" +#include "zk_proof_systems/zksnark/ram_zksnark/ram_zksnark_params.hpp" + +namespace libsnark { + +/** + * Runs the zkSNARK (generator, prover, and verifier) for a given + * RAM example (specified by an architecture, boot trace, auxiliary input, and time bound). + * + * Optionally, also test the serialization routines for keys and proofs. + * (This takes additional time.) + */ +template +bool run_ram_zksnark(const ram_example > &example, + const bool test_serialization); + +} // libsnark + +#include "zk_proof_systems/zksnark/ram_zksnark/examples/run_ram_zksnark.tcc" + +#endif // RUN_RAM_ZKSNARK_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/zksnark/ram_zksnark/examples/run_ram_zksnark.tcc b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/zksnark/ram_zksnark/examples/run_ram_zksnark.tcc new file mode 100644 index 0000000..5f16f27 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/zksnark/ram_zksnark/examples/run_ram_zksnark.tcc @@ -0,0 +1,83 @@ +/** @file + ***************************************************************************** + + Implementation of functionality that runs the RAM zkSNARK for + a given RAM example. + + See run_ram_zksnark.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef RUN_RAM_ZKSNARK_TCC_ +#define RUN_RAM_ZKSNARK_TCC_ + +#include "zk_proof_systems/zksnark/ram_zksnark/ram_zksnark.hpp" + +#include + +#include "common/profiling.hpp" + +namespace libsnark { + +/** + * The code below provides an example of all stages of running a RAM zkSNARK. + * + * Of course, in a real-life scenario, we would have three distinct entities, + * mangled into one in the demonstration below. The three entities are as follows. + * (1) The "generator", which runs the zkSNARK generator on input a given + * architecture. + * (2) The "prover", which runs the zkSNARK prover on input the proving key, + * a boot trace, and an auxiliary input. + * (3) The "verifier", which runs the zkSNARK verifier on input the verification key, + * a boot trace, a time bound, and a proof. + */ +template +bool run_ram_zksnark(const ram_example > &example, + const bool test_serialization) +{ + enter_block("Call to run_ram_zksnark"); + + printf("This run uses an example with the following parameters:\n"); + example.ap.print(); + printf("* Time bound (T): %zu\n", example.time_bound); + + print_header("RAM zkSNARK Generator"); + ram_zksnark_keypair keypair = ram_zksnark_generator(example.ap); + printf("\n"); print_indent(); print_mem("after generator"); + + if (test_serialization) + { + enter_block("Test serialization of keys"); + keypair.pk = reserialize >(keypair.pk); + keypair.vk = reserialize >(keypair.vk); + leave_block("Test serialization of keys"); + } + + print_header("RAM zkSNARK Prover"); + ram_zksnark_proof proof = ram_zksnark_prover(keypair.pk, example.boot_trace, example.time_bound, example.auxiliary_input); + printf("\n"); print_indent(); print_mem("after prover"); + + if (test_serialization) + { + enter_block("Test serialization of proof"); + proof = reserialize >(proof); + leave_block("Test serialization of proof"); + } + + print_header("RAM zkSNARK Verifier"); + bool ans = ram_zksnark_verifier(keypair.vk, example.boot_trace, example.time_bound, proof); + printf("\n"); print_indent(); print_mem("after verifier"); + printf("* The verification result is: %s\n", (ans ? "PASS" : "FAIL")); + + leave_block("Call to run_ram_zksnark"); + + return ans; +} + +} // libsnark + +#endif // RUN_RAM_ZKSNARK_TCC_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/zksnark/ram_zksnark/profiling/profile_ram_zksnark.cpp b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/zksnark/ram_zksnark/profiling/profile_ram_zksnark.cpp new file mode 100644 index 0000000..da72dff --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/zksnark/ram_zksnark/profiling/profile_ram_zksnark.cpp @@ -0,0 +1,178 @@ +/** + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ +#include "common/default_types/ram_zksnark_pp.hpp" +#include "relations/ram_computations/memory/examples/memory_contents_examples.hpp" +#include "relations/ram_computations/rams/examples/ram_examples.hpp" +#include "zk_proof_systems/zksnark/ram_zksnark/ram_zksnark.hpp" +#include "zk_proof_systems/zksnark/ram_zksnark/examples/run_ram_zksnark.hpp" +#include "relations/ram_computations/rams/tinyram/tinyram_params.hpp" + +#include + +using namespace libsnark; + +template +void simulate_random_memory_contents(const tinyram_architecture_params &ap, const size_t input_size, const size_t program_size) +{ + const size_t num_addresses = 1ul< dm_random(num_addresses, value_size, init_random); + leave_block("Initialize random delegated memory"); +} + +template +void profile_ram_zksnark_verifier(const tinyram_architecture_params &ap, const size_t input_size, const size_t program_size) +{ + typedef ram_zksnark_machine_pp ramT; + const size_t time_bound = 10; + + const size_t boot_trace_size_bound = program_size + input_size; + const ram_example example = gen_ram_example_complex(ap, boot_trace_size_bound, time_bound, true); + + ram_zksnark_proof pi; + ram_zksnark_verification_key vk = ram_zksnark_verification_key::dummy_verification_key(ap); + + enter_block("Verify fake proof"); + ram_zksnark_verifier(vk, example.boot_trace, time_bound, pi); + leave_block("Verify fake proof"); +} + +template +void print_ram_zksnark_verifier_profiling() +{ + inhibit_profiling_info = true; + for (size_t w : { 16, 32 }) + { + const size_t k = 16; + + for (size_t input_size : { 0, 10, 100 }) + { + for (size_t program_size = 10; program_size <= 10000; program_size *= 10) + { + const tinyram_architecture_params ap(w, k); + + profile_ram_zksnark_verifier(ap, input_size, program_size); + + const double input_map = last_times["Call to ram_zksnark_verifier_input_map"]; + const double preprocessing = last_times["Call to r1cs_ppzksnark_verifier_process_vk"]; + const double accumulate = last_times["Call to r1cs_ppzksnark_IC_query::accumulate"]; + const double pairings = last_times["Online pairing computations"]; + const double total = last_times["Call to ram_zksnark_verifier"]; + const double rest = total - (input_map + preprocessing + accumulate + pairings); + + const double delegated_ra_memory_init = last_times["Construct delegated_ra_memory from memory map"]; + simulate_random_memory_contents >(ap, input_size, program_size); + const double delegated_ra_memory_init_random = last_times["Initialize random delegated memory"]; + const double input_map_random = input_map - delegated_ra_memory_init + delegated_ra_memory_init_random; + const double total_random = total - delegated_ra_memory_init + delegated_ra_memory_init_random; + + printf("w = %zu, k = %zu, program_size = %zu, input_size = %zu, input_map = %0.2fms, preprocessing = %0.2fms, accumulate = %0.2fms, pairings = %0.2fms, rest = %0.2fms, total = %0.2fms (input_map_random = %0.2fms, total_random = %0.2fms)\n", + w, k, program_size, input_size, input_map * 1e-6, preprocessing * 1e-6, accumulate * 1e-6, pairings * 1e-6, rest * 1e-6, total * 1e-6, input_map_random * 1e-6, total_random * 1e-6); + } + } + } +} + +template +void profile_ram_zksnark(const tinyram_architecture_params &ap, const size_t program_size, const size_t input_size, const size_t time_bound) +{ + typedef ram_zksnark_machine_pp ramT; + + const size_t boot_trace_size_bound = program_size + input_size; + const ram_example example = gen_ram_example_complex(ap, boot_trace_size_bound, time_bound, true); + const bool test_serialization = true; + const bool bit = run_ram_zksnark(example, test_serialization); + assert(bit); +} + +namespace po = boost::program_options; + +bool process_command_line(const int argc, const char** argv, + bool &profile_gp, + size_t &w, + size_t &k, + bool &profile_v, + size_t &l) +{ + try + { + po::options_description desc("Usage"); + desc.add_options() + ("help", "print this help message") + ("profile_gp", "profile generator and prover") + ("w", po::value(&w)->default_value(16), "word size") + ("k", po::value(&k)->default_value(16), "register count") + ("profile_v", "profile verifier") + ("v", "print version info") + ("l", po::value(&l)->default_value(10), "program length"); + + po::variables_map vm; + po::store(po::parse_command_line(argc, argv, desc), vm); + + if (vm.count("v")) + { + print_compilation_info(); + exit(0); + } + + if (vm.count("help")) + { + std::cout << desc << "\n"; + return false; + } + + profile_gp = vm.count("profile_gp"); + profile_v = vm.count("profile_v"); + + if (!(vm.count("profile_gp") ^ vm.count("profile_v"))) + { + std::cout << "Must choose between profiling generator/prover and profiling verifier (see --help)\n"; + return false; + } + + po::notify(vm); + } + catch(std::exception& e) + { + std::cerr << "Error: " << e.what() << "\n"; + return false; + } + + return true; +} + +int main(int argc, const char* argv[]) +{ + start_profiling(); + ram_zksnark_PCD_pp::init_public_params(); + + bool profile_gp; + size_t w; + size_t k; + bool profile_v; + size_t l; + + if (!process_command_line(argc, argv, profile_gp, w, k, profile_v, l)) + { + return 1; + } + + tinyram_architecture_params ap(w, k); + + if (profile_gp) + { + profile_ram_zksnark(ap, 100, 100, 10); // w, k, l, n, T + } + + if (profile_v) + { + profile_ram_zksnark_verifier(ap, l/2, l/2); + } +} diff --git a/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/zksnark/ram_zksnark/ram_compliance_predicate.hpp b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/zksnark/ram_zksnark/ram_compliance_predicate.hpp new file mode 100644 index 0000000..9265c5a --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/zksnark/ram_zksnark/ram_compliance_predicate.hpp @@ -0,0 +1,248 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for a compliance predicate for RAM. + + The implementation follows, extends, and optimizes the approach described + in \[BCTV14]. + + Essentially, the RAM's CPU, which is expressed as an R1CS constraint system, + is augmented to obtain another R1CS constraint ssytem that implements a RAM + compliance predicate. This predicate is responsible for checking: + (1) transitions from a CPU state to the next; + (2) correct load/stores; and + (3) corner cases such as the first and last steps of the machine. + The first can be done by suitably embedding the RAM's CPU in the constraint + system. The second can be done by verifying authentication paths for the values + of memory. The third mostly consists of bookkeepng (with some subtleties arising + from the need to not break zero knowledge). + + The laying out of R1CS constraints is done via gadgetlib1 (a minimalistic + library for writing R1CS constraint systems). + + References: + + \[BCTV14]: + "Scalable Zero Knowledge via Cycles of Elliptic Curves", + Eli Ben-Sasson, Alessandro Chiesa, Eran Tromer, Madars Virza, + CRYPTO 2014, + + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef RAM_COMPLIANCE_PREDICATE_HPP_ +#define RAM_COMPLIANCE_PREDICATE_HPP_ + +#include "gadgetlib1/gadgets/delegated_ra_memory/memory_load_gadget.hpp" +#include "gadgetlib1/gadgets/delegated_ra_memory/memory_load_store_gadget.hpp" +#include "relations/ram_computations/memory/delegated_ra_memory.hpp" +#include "relations/ram_computations/rams/ram_params.hpp" +#include "zk_proof_systems/pcd/r1cs_pcd/compliance_predicate/compliance_predicate.hpp" +#include "zk_proof_systems/pcd/r1cs_pcd/compliance_predicate/cp_handler.hpp" + +namespace libsnark { + +/** + * A RAM message specializes the generic PCD message, in order to + * obtain a more user-friendly print method. + */ +template +class ram_pcd_message : public r1cs_pcd_message > { +private: + void print_bits(const bit_vector &bv) const; + +public: + typedef ram_base_field FieldT; + + ram_architecture_params ap; + + size_t timestamp; + bit_vector root_initial; + bit_vector root; + size_t pc_addr; + bit_vector cpu_state; + size_t pc_addr_initial; + bit_vector cpu_state_initial; + bool has_accepted; + + ram_pcd_message(const size_t type, + const ram_architecture_params &ap, + const size_t timestamp, + const bit_vector root_initial, + const bit_vector root, + const size_t pc_addr, + const bit_vector cpu_state, + const size_t pc_addr_initial, + const bit_vector cpu_state_initial, + const bool has_accepted); + + bit_vector unpacked_payload_as_bits() const; + r1cs_variable_assignment payload_as_r1cs_variable_assignment() const; + void print() const; + + static size_t unpacked_payload_size_in_bits(const ram_architecture_params &ap); +}; + +template +class ram_pcd_message_variable : public r1cs_pcd_message_variable > { +public: + ram_architecture_params ap; + + typedef ram_base_field FieldT; + + pb_variable_array packed_payload; + + pb_variable_array timestamp; + pb_variable_array root_initial; + pb_variable_array root; + pb_variable_array pc_addr; + pb_variable_array cpu_state; + pb_variable_array pc_addr_initial; + pb_variable_array cpu_state_initial; + pb_variable has_accepted; + + pb_variable_array all_unpacked_vars; + + std::shared_ptr > unpack_payload; + + ram_pcd_message_variable(protoboard &pb, + const ram_architecture_params &ap, + const std::string &annotation_prefix); + + void allocate_unpacked_part(); + void generate_r1cs_constraints(); + void generate_r1cs_witness_from_bits(); + void generate_r1cs_witness_from_packed(); + + std::shared_ptr > get_message() const; +}; + +template +class ram_pcd_local_data : public r1cs_pcd_local_data > { +public: + typedef ram_base_field FieldT; + + bool is_halt_case; + + delegated_ra_memory > &mem; + typename ram_input_tape::const_iterator &aux_it; + const typename ram_input_tape::const_iterator &aux_end; + + ram_pcd_local_data(const bool is_halt_case, + delegated_ra_memory > &mem, + typename ram_input_tape::const_iterator &aux_it, + const typename ram_input_tape::const_iterator &aux_end); + + r1cs_variable_assignment as_r1cs_variable_assignment() const; +}; + +template +class ram_pcd_local_data_variable : public r1cs_pcd_local_data_variable > { +public: + typedef ram_base_field FieldT; + + pb_variable is_halt_case; + + ram_pcd_local_data_variable(protoboard &pb, + const std::string &annotation_prefix); +}; + +/** + * A RAM compliance predicate. + */ +template +class ram_compliance_predicate_handler : public compliance_predicate_handler, ram_protoboard > { +protected: + + ram_architecture_params ap; + +public: + + typedef ram_base_field FieldT; + typedef CRH_with_bit_out_gadget HashT; + typedef compliance_predicate_handler, ram_protoboard > base_handler; + + std::shared_ptr > next; + std::shared_ptr > cur; +private: + + pb_variable zero; // TODO: promote linear combinations to first class objects + std::shared_ptr > copy_root_initial; + std::shared_ptr > copy_pc_addr_initial; + std::shared_ptr > copy_cpu_state_initial; + + pb_variable is_base_case; + pb_variable is_not_halt_case; + + pb_variable packed_cur_timestamp; + std::shared_ptr > pack_cur_timestamp; + pb_variable packed_next_timestamp; + std::shared_ptr > pack_next_timestamp; + + pb_variable_array zero_cpu_state; + pb_variable_array zero_pc_addr; + pb_variable_array zero_root; + + std::shared_ptr > initialize_cur_cpu_state; + std::shared_ptr > initialize_prev_pc_addr; + + std::shared_ptr > initialize_root; + + pb_variable_array prev_pc_val; + std::shared_ptr > prev_pc_val_digest; + std::shared_ptr > cur_root_digest; + std::shared_ptr > instruction_fetch_merkle_proof; + std::shared_ptr > instruction_fetch; + + std::shared_ptr > next_root_digest; + + pb_variable_array ls_addr; + pb_variable_array ls_prev_val; + pb_variable_array ls_next_val; + std::shared_ptr > ls_prev_val_digest; + std::shared_ptr > ls_next_val_digest; + std::shared_ptr > load_merkle_proof; + std::shared_ptr > store_merkle_proof; + std::shared_ptr > load_store_checker; + + pb_variable_array temp_next_pc_addr; + pb_variable_array temp_next_cpu_state; + std::shared_ptr > cpu_checker; + + pb_variable do_halt; + std::shared_ptr > clear_next_root; + std::shared_ptr > clear_next_pc_addr; + std::shared_ptr > clear_next_cpu_state; + + std::shared_ptr > copy_temp_next_root; + std::shared_ptr > copy_temp_next_pc_addr; + std::shared_ptr > copy_temp_next_cpu_state; + +public: + const size_t addr_size; + const size_t value_size; + const size_t digest_size; + + size_t message_length; + + ram_compliance_predicate_handler(const ram_architecture_params &ap); + void generate_r1cs_constraints(); + void generate_r1cs_witness(const std::vector > > &incoming_message_values, + const std::shared_ptr > &local_data_value); + + static std::shared_ptr > get_base_case_message(const ram_architecture_params &ap, + const ram_boot_trace &primary_input); + static std::shared_ptr > get_final_case_msg(const ram_architecture_params &ap, + const ram_boot_trace &primary_input, + const size_t time_bound); +}; + +} // libsnark + +#include "zk_proof_systems/zksnark/ram_zksnark/ram_compliance_predicate.tcc" + +#endif // RAM_COMPLIANCE_PREDICATE_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/zksnark/ram_zksnark/ram_compliance_predicate.tcc b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/zksnark/ram_zksnark/ram_compliance_predicate.tcc new file mode 100644 index 0000000..cbaf8a2 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/zksnark/ram_zksnark/ram_compliance_predicate.tcc @@ -0,0 +1,715 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for a compliance predicate for RAM. + + See ram_compliance_predicate.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef RAM_COMPLIANCE_PREDICATE_TCC_ +#define RAM_COMPLIANCE_PREDICATE_TCC_ + +namespace libsnark { + +template +ram_pcd_message::ram_pcd_message(const size_t type, + const ram_architecture_params &ap, + const size_t timestamp, + const bit_vector root_initial, + const bit_vector root, + const size_t pc_addr, + const bit_vector cpu_state, + const size_t pc_addr_initial, + const bit_vector cpu_state_initial, + const bool has_accepted) : + r1cs_pcd_message(type), + ap(ap), + timestamp(timestamp), + root_initial(root_initial), + root(root), + pc_addr(pc_addr), + cpu_state(cpu_state), + pc_addr_initial(pc_addr_initial), + cpu_state_initial(cpu_state_initial), + has_accepted(has_accepted) +{ + const size_t digest_size = CRH_with_bit_out_gadget::get_digest_len(); + assert(log2(timestamp) < ramT::timestamp_length); + assert(root_initial.size() == digest_size); + assert(root.size() == digest_size); + assert(log2(pc_addr) < ap.address_size()); + assert(cpu_state.size() == ap.cpu_state_size()); + assert(log2(pc_addr_initial) < ap.address_size()); + assert(cpu_state_initial.size() == ap.cpu_state_size()); +} + +template +bit_vector ram_pcd_message::unpacked_payload_as_bits() const +{ + bit_vector result; + + const bit_vector timestamp_bits = convert_field_element_to_bit_vector(FieldT(timestamp), ramT::timestamp_length); + const bit_vector pc_addr_bits = convert_field_element_to_bit_vector(FieldT(pc_addr), ap.address_size()); + const bit_vector pc_addr_initial_bits = convert_field_element_to_bit_vector(FieldT(pc_addr_initial), ap.address_size()); + + result.insert(result.end(), timestamp_bits.begin(), timestamp_bits.end()); + result.insert(result.end(), root_initial.begin(), root_initial.end()); + result.insert(result.end(), root.begin(), root.end()); + result.insert(result.end(), pc_addr_bits.begin(), pc_addr_bits.end()); + result.insert(result.end(), cpu_state.begin(), cpu_state.end()); + result.insert(result.end(), pc_addr_initial_bits.begin(), pc_addr_initial_bits.end()); + result.insert(result.end(), cpu_state_initial.begin(), cpu_state_initial.end()); + result.insert(result.end(), has_accepted); + + assert(result.size() == unpacked_payload_size_in_bits(ap)); + return result; +} + +template +r1cs_variable_assignment > ram_pcd_message::payload_as_r1cs_variable_assignment() const +{ + const bit_vector payload_bits = unpacked_payload_as_bits(); + const r1cs_variable_assignment result = pack_bit_vector_into_field_element_vector(payload_bits); + return result; +} + +template +void ram_pcd_message::print_bits(const bit_vector &bv) const +{ + for (bool b : bv) + { + printf("%d", b ? 1 : 0); + } + printf("\n"); +} + +template +void ram_pcd_message::print() const +{ + printf("ram_pcd_message:\n"); + printf(" type: %zu\n", this->type); + printf(" timestamp: %zu\n", timestamp); + printf(" root_initial: "); + print_bits(root_initial); + printf(" root: "); + print_bits(root); + printf(" pc_addr: %zu\n", pc_addr); + printf(" cpu_state: "); + print_bits(cpu_state); + printf(" pc_addr_initial: %zu\n", pc_addr_initial); + printf(" cpu_state_initial: "); + print_bits(cpu_state_initial); + printf(" has_accepted: %s\n", has_accepted ? "YES" : "no"); +} + +template +size_t ram_pcd_message::unpacked_payload_size_in_bits(const ram_architecture_params &ap) +{ + const size_t digest_size = CRH_with_bit_out_gadget::get_digest_len(); + + return (ramT::timestamp_length + // timestamp + 2*digest_size + // root, root_initial + 2*ap.address_size() + // pc_addr, pc_addr_initial + 2*ap.cpu_state_size() + // cpu_state, cpu_state_initial + 1); // has_accepted +} + +template +ram_pcd_message_variable::ram_pcd_message_variable(protoboard &pb, + const ram_architecture_params &ap, + const std::string &annotation_prefix) : + r1cs_pcd_message_variable >(pb, annotation_prefix), ap(ap) +{ + const size_t unpacked_payload_size_in_bits = ram_pcd_message::unpacked_payload_size_in_bits(ap); + const size_t packed_payload_size = div_ceil(unpacked_payload_size_in_bits, FieldT::capacity()); + packed_payload.allocate(pb, packed_payload_size, FMT(annotation_prefix, " packed_payload")); + + this->update_all_vars(); +} + +template +void ram_pcd_message_variable::allocate_unpacked_part() +{ + const size_t digest_size = CRH_with_bit_out_gadget::get_digest_len(); + + timestamp.allocate(this->pb, ramT::timestamp_length, FMT(this->annotation_prefix, " timestamp")); + root_initial.allocate(this->pb, digest_size, FMT(this->annotation_prefix, " root_initial")); + root.allocate(this->pb, digest_size, FMT(this->annotation_prefix, " root")); + pc_addr.allocate(this->pb, ap.address_size(), FMT(this->annotation_prefix, " pc_addr")); + cpu_state.allocate(this->pb, ap.cpu_state_size(), FMT(this->annotation_prefix, " cpu_state")); + pc_addr_initial.allocate(this->pb, ap.address_size(), FMT(this->annotation_prefix, " pc_addr_initial")); + cpu_state_initial.allocate(this->pb, ap.cpu_state_size(), FMT(this->annotation_prefix, " cpu_state_initial")); + has_accepted.allocate(this->pb, FMT(this->annotation_prefix, " has_accepted")); + + all_unpacked_vars.insert(all_unpacked_vars.end(), timestamp.begin(), timestamp.end()); + all_unpacked_vars.insert(all_unpacked_vars.end(), root_initial.begin(), root_initial.end()); + all_unpacked_vars.insert(all_unpacked_vars.end(), root.begin(), root.end()); + all_unpacked_vars.insert(all_unpacked_vars.end(), pc_addr.begin(), pc_addr.end()); + all_unpacked_vars.insert(all_unpacked_vars.end(), cpu_state.begin(), cpu_state.end()); + all_unpacked_vars.insert(all_unpacked_vars.end(), pc_addr_initial.begin(), pc_addr_initial.end()); + all_unpacked_vars.insert(all_unpacked_vars.end(), cpu_state_initial.begin(), cpu_state_initial.end()); + all_unpacked_vars.insert(all_unpacked_vars.end(), has_accepted); + + unpack_payload.reset(new multipacking_gadget(this->pb, all_unpacked_vars, packed_payload, FieldT::capacity(), FMT(this->annotation_prefix, " unpack_payload"))); +} + +template +void ram_pcd_message_variable::generate_r1cs_witness_from_bits() +{ + unpack_payload->generate_r1cs_witness_from_bits(); +} + +template +void ram_pcd_message_variable::generate_r1cs_witness_from_packed() +{ + unpack_payload->generate_r1cs_witness_from_packed(); +} + +template +void ram_pcd_message_variable::generate_r1cs_constraints() +{ + unpack_payload->generate_r1cs_constraints(true); +} + +template +std::shared_ptr > > ram_pcd_message_variable::get_message() const +{ + const size_t type_val = this->pb.val(this->type).as_ulong(); + const size_t timestamp_val = timestamp.get_field_element_from_bits(this->pb).as_ulong(); + const bit_vector root_initial_val = root_initial.get_bits(this->pb); + const bit_vector root_val = root.get_bits(this->pb); + const size_t pc_addr_val = pc_addr.get_field_element_from_bits(this->pb).as_ulong(); + const bit_vector cpu_state_val = cpu_state.get_bits(this->pb); + const size_t pc_addr_initial_val = pc_addr_initial.get_field_element_from_bits(this->pb).as_ulong(); + const bit_vector cpu_state_initial_val = cpu_state_initial.get_bits(this->pb); + const bool has_accepted_val = (this->pb.val(has_accepted) == FieldT::one()); + + std::shared_ptr > result; + result.reset(new ram_pcd_message(type_val, + ap, + timestamp_val, + root_initial_val, + root_val, + pc_addr_val, + cpu_state_val, + pc_addr_initial_val, + cpu_state_initial_val, + has_accepted_val)); + return result; +} + +template +ram_pcd_local_data::ram_pcd_local_data(const bool is_halt_case, + delegated_ra_memory > &mem, + typename ram_input_tape::const_iterator &aux_it, + const typename ram_input_tape::const_iterator &aux_end) : + is_halt_case(is_halt_case), mem(mem), aux_it(aux_it), aux_end(aux_end) +{ +} + +template +r1cs_variable_assignment > ram_pcd_local_data::as_r1cs_variable_assignment() const +{ + r1cs_variable_assignment result; + result.emplace_back(is_halt_case ? FieldT::one() : FieldT::zero()); + return result; +} + +template +ram_pcd_local_data_variable::ram_pcd_local_data_variable(protoboard &pb, + const std::string &annotation_prefix) : + r1cs_pcd_local_data_variable >(pb, annotation_prefix) +{ + is_halt_case.allocate(pb, FMT(annotation_prefix, " is_halt_case")); + + this->update_all_vars(); +} + +/* + We need to perform the following checks: + + Always: + next.root_initial = cur.root_initial + next.pc_addr_init = cur.pc_addr_initial + next.cpu_state_initial = cur.cpu_state_initial + + If is_is_base_case = 1: (base case) + that cur.timestamp = 0, cur.cpu_state = cpu_state_init, cur.pc_addr = pc_addr_initial, cur.has_accepted = 0 + that cur.root = cur.root_initial + + If do_halt = 0: (regular case) + that instruction fetch was correctly executed + next.timestamp = cur.timestamp + 1 + that CPU accepted on (cur, temp) + that load-then-store was correctly handled + that next.root = temp.root, next.cpu_state = temp.cpu_state, next.pc_addr = temp.pc_addr + + If do_halt = 1: (final case) + that cur.has_accepted = 1 + that next.root = 0, next.cpu_state = 0, next.pc_addr = 0 + that next.timestamp = cur.timestamp and next.has_accepted = cur.has_accepted +*/ + +template +ram_compliance_predicate_handler::ram_compliance_predicate_handler(const ram_architecture_params &ap) : + compliance_predicate_handler, ram_protoboard >(ram_protoboard(ap), + 100, + 1, + 1, + true, + std::set{1}), + ap(ap), + addr_size(ap.address_size()), + value_size(ap.value_size()), + digest_size(CRH_with_bit_out_gadget::get_digest_len()) +{ + // TODO: assert that message has fields of lengths consistent with num_addresses/value_size (as a method for ram_message) + // choose a constant for timestamp_len + // check that value_size <= digest_size; digest_size is not assumed to fit in chunk size (more precisely, it is handled correctly in the other gadgets). + // check if others fit (timestamp_length, value_size, addr_size) + + // the variables allocated are: next, cur, local data (nil for us), is_base_case, witness + + this->outgoing_message.reset(new ram_pcd_message_variable(this->pb, ap, "outgoing_message")); + this->arity.allocate(this->pb, "arity"); + this->incoming_messages[0].reset(new ram_pcd_message_variable(this->pb, ap, "incoming_message")); + this->local_data.reset(new ram_pcd_local_data_variable(this->pb, "local_data")); + + is_base_case.allocate(this->pb, "is_base_case"); + + next = std::dynamic_pointer_cast >(this->outgoing_message); + cur = std::dynamic_pointer_cast >(this->incoming_messages[0]); + + next->allocate_unpacked_part(); + cur->allocate_unpacked_part(); + + // work-around for bad linear combination handling + zero.allocate(this->pb, "zero"); // will go away when we properly support linear terms + + temp_next_pc_addr.allocate(this->pb, addr_size, "temp_next_pc_addr"); + temp_next_cpu_state.allocate(this->pb, ap.cpu_state_size(), "temp_next_cpu_state"); + + const size_t chunk_size = FieldT::capacity(); + + /* + Always: + next.root_initial = cur.root_initial + next.pc_addr_init = cur.pc_addr_initial + next.cpu_state_initial = cur.cpu_state_initial + */ + copy_root_initial.reset(new bit_vector_copy_gadget(this->pb, cur->root_initial, next->root_initial, ONE, chunk_size, "copy_root_initial")); + copy_pc_addr_initial.reset(new bit_vector_copy_gadget(this->pb, cur->pc_addr_initial, next->pc_addr_initial, ONE, chunk_size, "copy_pc_addr_initial")); + copy_cpu_state_initial.reset(new bit_vector_copy_gadget(this->pb, cur->cpu_state_initial, next->cpu_state_initial, ONE, chunk_size, "copy_cpu_state_initial")); + + /* + If is_base_case = 1: (base case) + that cur.timestamp = 0, cur.cpu_state = 0, cur.pc_addr = 0, cur.has_accepted = 0 + that cur.root = cur.root_initial + */ + packed_cur_timestamp.allocate(this->pb, "packed_cur_timestamp"); + pack_cur_timestamp.reset(new packing_gadget(this->pb, cur->timestamp, packed_cur_timestamp, "pack_cur_timestamp")); + + zero_cpu_state = pb_variable_array(cur->cpu_state.size(), zero); + zero_pc_addr = pb_variable_array(cur->pc_addr.size(), zero); + + initialize_cur_cpu_state.reset(new bit_vector_copy_gadget(this->pb, cur->cpu_state_initial, cur->cpu_state, is_base_case, chunk_size, "initialize_cur_cpu_state")); + initialize_prev_pc_addr.reset(new bit_vector_copy_gadget(this->pb, cur->pc_addr_initial, cur->pc_addr, is_base_case, chunk_size, "initialize_prev_pc_addr")); + + initialize_root.reset(new bit_vector_copy_gadget(this->pb, cur->root_initial, cur->root, is_base_case, chunk_size, "initialize_root")); + /* + If do_halt = 0: (regular case) + that instruction fetch was correctly executed + next.timestamp = cur.timestamp + 1 + that CPU accepted on (cur, next) + that load-then-store was correctly handled + */ + is_not_halt_case.allocate(this->pb, "is_not_halt_case"); + // for performing instruction fetch + prev_pc_val.allocate(this->pb, value_size, "prev_pc_val"); + prev_pc_val_digest.reset(new digest_variable(this->pb, digest_size, prev_pc_val, zero, "prev_pc_val_digest")); + cur_root_digest.reset(new digest_variable(this->pb, digest_size, cur->root, zero, "cur_root_digest")); + instruction_fetch_merkle_proof.reset(new merkle_authentication_path_variable(this->pb, addr_size, "instruction_fetch_merkle_proof")); + instruction_fetch.reset(new memory_load_gadget(this->pb, addr_size, + cur->pc_addr, + *prev_pc_val_digest, + *cur_root_digest, + *instruction_fetch_merkle_proof, + ONE, + "instruction_fetch")); + + // for next.timestamp = cur.timestamp + 1 + packed_next_timestamp.allocate(this->pb, "packed_next_timestamp"); + pack_next_timestamp.reset(new packing_gadget(this->pb, next->timestamp, packed_next_timestamp, "pack_next_timestamp")); + + // that CPU accepted on (cur, temp) + ls_addr.allocate(this->pb, addr_size, "ls_addr"); + ls_prev_val.allocate(this->pb, value_size, "ls_prev_val"); + ls_next_val.allocate(this->pb, value_size, "ls_next_val"); + cpu_checker.reset(new ram_cpu_checker(this->pb, cur->pc_addr, prev_pc_val, cur->cpu_state, + ls_addr, ls_prev_val, ls_next_val, + temp_next_cpu_state, temp_next_pc_addr, next->has_accepted, + "cpu_checker")); + + // that load-then-store was correctly handled + ls_prev_val_digest.reset(new digest_variable(this->pb, digest_size, ls_prev_val, zero, "ls_prev_val_digest")); + ls_next_val_digest.reset(new digest_variable(this->pb, digest_size, ls_next_val, zero, "ls_next_val_digest")); + next_root_digest.reset(new digest_variable(this->pb, digest_size, next->root, zero, "next_root_digest")); + load_merkle_proof.reset(new merkle_authentication_path_variable(this->pb, addr_size, "load_merkle_proof")); + store_merkle_proof.reset(new merkle_authentication_path_variable(this->pb, addr_size, "store_merkle_proof")); + load_store_checker.reset(new memory_load_store_gadget(this->pb, addr_size, ls_addr, + *ls_prev_val_digest, *cur_root_digest, *load_merkle_proof, + *ls_next_val_digest, *next_root_digest, *store_merkle_proof, is_not_halt_case, + "load_store_checker")); + /* + If do_halt = 1: (final case) + that cur.has_accepted = 1 + that next.root = 0, next.cpu_state = 0, next.pc_addr = 0 + that next.timestamp = cur.timestamp and next.has_accepted = cur.has_accepted + */ + do_halt.allocate(this->pb, "do_halt"); + zero_root = pb_variable_array(next->root.size(), zero); + clear_next_root.reset(new bit_vector_copy_gadget(this->pb, zero_root, next->root, do_halt, chunk_size, "clear_next_root")); + clear_next_pc_addr.reset(new bit_vector_copy_gadget(this->pb, zero_pc_addr, next->pc_addr, do_halt, chunk_size, "clear_next_pc_addr")); + clear_next_cpu_state.reset(new bit_vector_copy_gadget(this->pb, zero_cpu_state, next->cpu_state, do_halt, chunk_size, "clear_cpu_state")); + + copy_temp_next_pc_addr.reset(new bit_vector_copy_gadget(this->pb, temp_next_pc_addr, next->pc_addr, is_not_halt_case, chunk_size, "copy_temp_next_pc_addr")); + copy_temp_next_cpu_state.reset(new bit_vector_copy_gadget(this->pb, temp_next_cpu_state, next->cpu_state, is_not_halt_case, chunk_size, "copy_temp_next_cpu_state")); +} + +template +void ram_compliance_predicate_handler::generate_r1cs_constraints() +{ + print_indent(); printf("* Message size: %zu\n", next->all_vars.size()); + print_indent(); printf("* Address size: %zu\n", addr_size); + print_indent(); printf("* CPU state size: %zu\n", ap.cpu_state_size()); + print_indent(); printf("* Digest size: %zu\n", digest_size); + + PROFILE_CONSTRAINTS(this->pb, "handle next_type, arity and cur_type") + { + generate_r1cs_equals_const_constraint(this->pb, next->type, FieldT::one(), "next_type"); + generate_r1cs_equals_const_constraint(this->pb, this->arity, FieldT::one(), "arity"); + this->pb.add_r1cs_constraint(r1cs_constraint(is_base_case, cur->type, 0), "nonzero_cur_type_implies_base_case_0"); + generate_boolean_r1cs_constraint(this->pb, cur->type, "cur_type_boolean"); + generate_boolean_r1cs_constraint(this->pb, is_base_case, "is_base_case_boolean"); + } + + PROFILE_CONSTRAINTS(this->pb, "unpack messages") + { + next->generate_r1cs_constraints(); + cur->generate_r1cs_constraints(); + } + + // work-around for bad linear combination handling + generate_r1cs_equals_const_constraint(this->pb, zero, FieldT::zero(), " zero"); + + /* recall that Booleanity of PCD messages has already been enforced by the PCD machine, which is explains the absence of Booleanity checks */ + /* + We need to perform the following checks: + + Always: + next.root_initial = cur.root_initial + next.pc_addr_init = cur.pc_addr_initial + next.cpu_state_initial = cur.cpu_state_initial + */ + PROFILE_CONSTRAINTS(this->pb, "copy root_initial") + { + copy_root_initial->generate_r1cs_constraints(false, false); + } + + PROFILE_CONSTRAINTS(this->pb, "copy pc_addr_initial and cpu_state_initial") + { + copy_pc_addr_initial->generate_r1cs_constraints(false, false); + copy_cpu_state_initial->generate_r1cs_constraints(false, false); + } + + /* + If is_base_case = 1: (base case) + that cur.timestamp = 0, cur.cpu_state = 0, cur.pc_addr = 0, cur.has_accepted = 0 + that cur.root = cur.root_initial + */ + pack_cur_timestamp->generate_r1cs_constraints(false); + this->pb.add_r1cs_constraint(r1cs_constraint(is_base_case, packed_cur_timestamp, 0), "clear_ts_on_is_base_case"); + PROFILE_CONSTRAINTS(this->pb, "copy cur_cpu_state and prev_pc_addr") + { + initialize_cur_cpu_state->generate_r1cs_constraints(false, false); + initialize_prev_pc_addr->generate_r1cs_constraints(false, false); + } + this->pb.add_r1cs_constraint(r1cs_constraint(is_base_case, cur->has_accepted, 0), "is_base_case_is_not_accepting"); + PROFILE_CONSTRAINTS(this->pb, "initialize root") + { + initialize_root->generate_r1cs_constraints(false, false); + } + + /* + If do_halt = 0: (regular case) + that instruction fetch was correctly executed + next.timestamp = cur.timestamp + 1 + that CPU accepted on (cur, next) + that load-then-store was correctly handled + that next.root = temp.root, next.cpu_state = temp.cpu_state, next.pc_addr = temp.pc_addr + */ + this->pb.add_r1cs_constraint(r1cs_constraint(1, 1 - do_halt, is_not_halt_case), "is_not_halt_case"); + PROFILE_CONSTRAINTS(this->pb, "instruction fetch") + { + instruction_fetch_merkle_proof->generate_r1cs_constraints(); + instruction_fetch->generate_r1cs_constraints(); + } + pack_next_timestamp->generate_r1cs_constraints(false); + this->pb.add_r1cs_constraint(r1cs_constraint(is_not_halt_case, (packed_cur_timestamp + 1) - packed_next_timestamp, 0), "increment_timestamp"); + PROFILE_CONSTRAINTS(this->pb, "CPU checker") + { + cpu_checker->generate_r1cs_constraints(); + } + PROFILE_CONSTRAINTS(this->pb, "load/store checker") + { + // See comment in merkle_tree_check_update_gadget::generate_r1cs_witness() for why we don't need to call store_merkle_proof->generate_r1cs_constraints() + load_merkle_proof->generate_r1cs_constraints(); + load_store_checker->generate_r1cs_constraints(); + } + + PROFILE_CONSTRAINTS(this->pb, "copy temp_next_pc_addr and temp_next_cpu_state") + { + copy_temp_next_pc_addr->generate_r1cs_constraints(true, false); + copy_temp_next_cpu_state->generate_r1cs_constraints(true, false); + } + + /* + If do_halt = 1: (final case) + that cur.has_accepted = 1 + that next.root = 0, next.cpu_state = 0, next.pc_addr = 0 + that next.timestamp = cur.timestamp and next.has_accepted = cur.has_accepted + */ + this->pb.add_r1cs_constraint(r1cs_constraint(do_halt, 1 - cur->has_accepted, 0), "final_case_must_be_accepting"); + + PROFILE_CONSTRAINTS(this->pb, "clear next root") + { + clear_next_root->generate_r1cs_constraints(false, false); + } + + PROFILE_CONSTRAINTS(this->pb, "clear next_pc_addr and next_cpu_state") + { + clear_next_pc_addr->generate_r1cs_constraints(false, false); + clear_next_cpu_state->generate_r1cs_constraints(false, false); + } + + this->pb.add_r1cs_constraint(r1cs_constraint(do_halt, packed_cur_timestamp - packed_next_timestamp, 0), "equal_ts_on_halt"); + + const size_t accounted = PRINT_CONSTRAINT_PROFILING(); + const size_t total = this->pb.num_constraints(); + print_indent(); printf("* Unaccounted constraints: %zu\n", total - accounted); + print_indent(); printf("* Number of constraints in ram_compliance_predicate: %zu\n", total); +} + +template +void ram_compliance_predicate_handler::generate_r1cs_witness(const std::vector > > &incoming_message_values, + const std::shared_ptr > &local_data_value) +{ + const std::shared_ptr > ram_local_data_value = std::dynamic_pointer_cast >(local_data_value); + assert(ram_local_data_value->mem.num_addresses == 1ul << addr_size); // check value_size and num_addresses too + + base_handler::generate_r1cs_witness(incoming_message_values, local_data_value); + cur->generate_r1cs_witness_from_packed(); + + this->pb.val(next->type) = FieldT::one(); + this->pb.val(this->arity) = FieldT::one(); + this->pb.val(is_base_case) = (this->pb.val(cur->type) == FieldT::zero() ? FieldT::one() : FieldT::zero()); + + this->pb.val(zero) = FieldT::zero(); + /* + Always: + next.root_initial = cur.root_initial + next.pc_addr_init = cur.pc_addr_initial + next.cpu_state_initial = cur.cpu_state_initial + */ + copy_root_initial->generate_r1cs_witness(); + for (size_t i = 0 ; i < next->root_initial.size(); ++i) + { + this->pb.val(cur->root_initial[i]).print(); + this->pb.val(next->root_initial[i]).print(); + assert(this->pb.val(cur->root_initial[i]) == this->pb.val(next->root_initial[i])); + } + + copy_pc_addr_initial->generate_r1cs_witness(); + copy_cpu_state_initial->generate_r1cs_witness(); + + /* + If is_base_case = 1: (base case) + that cur.timestamp = 0, cur.cpu_state = 0, cur.pc_addr = 0, cur.has_accepted = 0 + that cur.root = cur.root_initial + */ + const bool base_case = (incoming_message_values[0]->type == 0); + this->pb.val(is_base_case) = base_case ? FieldT::one() : FieldT::zero(); + + initialize_cur_cpu_state->generate_r1cs_witness(); + initialize_prev_pc_addr->generate_r1cs_witness(); + + if (base_case) + { + this->pb.val(packed_cur_timestamp) = FieldT::zero(); + this->pb.val(cur->has_accepted) = FieldT::zero(); + pack_cur_timestamp->generate_r1cs_witness_from_packed(); + } + else + { + pack_cur_timestamp->generate_r1cs_witness_from_bits(); + } + + initialize_root->generate_r1cs_witness(); + + /* + If do_halt = 0: (regular case) + that instruction fetch was correctly executed + next.timestamp = cur.timestamp + 1 + that CPU accepted on (cur, temp) + that load-then-store was correctly handled + */ + this->pb.val(do_halt) = ram_local_data_value->is_halt_case ? FieldT::one() : FieldT::zero(); + this->pb.val(is_not_halt_case) = FieldT::one() - this->pb.val(do_halt); + + // that instruction fetch was correctly executed + const size_t int_pc_addr = convert_bit_vector_to_field_element(cur->pc_addr.get_bits(this->pb)).as_ulong(); + const size_t int_pc_val = ram_local_data_value->mem.get_value(int_pc_addr); +#ifdef DEBUG + printf("pc_addr (in units) = %zu, pc_val = %zu (0x%08zx)\n", int_pc_addr, int_pc_val, int_pc_val); +#endif + bit_vector pc_val_bv = int_list_to_bits({ int_pc_val }, value_size); + std::reverse(pc_val_bv.begin(), pc_val_bv.end()); + + prev_pc_val.fill_with_bits(this->pb, pc_val_bv); + const merkle_authentication_path pc_path = ram_local_data_value->mem.get_path(int_pc_addr); + instruction_fetch_merkle_proof->generate_r1cs_witness(int_pc_addr, pc_path); + instruction_fetch->generate_r1cs_witness(); + + // next.timestamp = cur.timestamp + 1 (or cur.timestamp if do_halt) + this->pb.val(packed_next_timestamp) = this->pb.val(packed_cur_timestamp) + this->pb.val(is_not_halt_case); + pack_next_timestamp->generate_r1cs_witness_from_packed(); + + // that CPU accepted on (cur, temp) + // Step 1: Get address and old witnesses for delegated memory. + cpu_checker->generate_r1cs_witness_address(); + const size_t int_ls_addr = ls_addr.get_field_element_from_bits(this->pb).as_ulong(); + const size_t int_ls_prev_val = ram_local_data_value->mem.get_value(int_ls_addr); + const merkle_authentication_path prev_path = ram_local_data_value->mem.get_path(int_ls_addr); + ls_prev_val.fill_with_bits_of_ulong(this->pb, int_ls_prev_val); + assert(ls_prev_val.get_field_element_from_bits(this->pb) == FieldT(int_ls_prev_val, true)); + // Step 2: Execute CPU checker and delegated memory + cpu_checker->generate_r1cs_witness_other(ram_local_data_value->aux_it, ram_local_data_value->aux_end); +#ifdef DEBUG + printf("Debugging information from transition function:\n"); + cpu_checker->dump(); +#endif + const size_t int_ls_next_val = ls_next_val.get_field_element_from_bits(this->pb).as_ulong(); + ram_local_data_value->mem.set_value(int_ls_addr, int_ls_next_val); +#ifdef DEBUG + printf("Memory location %zu changed from %zu (0x%08zx) to %zu (0x%08zx)\n", int_ls_addr, int_ls_prev_val, int_ls_prev_val, int_ls_next_val, int_ls_next_val); +#endif + // Step 4: Use both to satisfy load_store_checker + load_merkle_proof->generate_r1cs_witness(int_ls_addr, prev_path); + load_store_checker->generate_r1cs_witness(); + + /* + If do_halt = 1: (final case) + that cur.has_accepted = 1 + that next.root = 0, next.cpu_state = 0, next.pc_addr = 0 + that next.timestamp = cur.timestamp and next.has_accepted = cur.has_accepted + */ + + // Order matters here: both witness maps touch next_root, but the + // one that does not set values must be executed the last, so its + // auxiliary variables are filled in correctly according to values + // actually set by the other witness map. + if (this->pb.val(do_halt).is_zero()) + { + copy_temp_next_pc_addr->generate_r1cs_witness(); + copy_temp_next_cpu_state->generate_r1cs_witness(); + + clear_next_root->generate_r1cs_witness(); + clear_next_pc_addr->generate_r1cs_witness(); + clear_next_cpu_state->generate_r1cs_witness(); + } + else + { + clear_next_root->generate_r1cs_witness(); + clear_next_pc_addr->generate_r1cs_witness(); + clear_next_cpu_state->generate_r1cs_witness(); + + copy_temp_next_pc_addr->generate_r1cs_witness(); + copy_temp_next_cpu_state->generate_r1cs_witness(); + } + +#ifdef DEBUG + printf("next.has_accepted: "); + this->pb.val(next->has_accepted).print(); +#endif + + next->generate_r1cs_witness_from_bits(); +} + +template +std::shared_ptr > > ram_compliance_predicate_handler::get_base_case_message(const ram_architecture_params &ap, + const ram_boot_trace &primary_input) +{ + enter_block("Call to ram_compliance_predicate_handler::get_base_case_message"); + const size_t num_addresses = 1ul << ap.address_size(); + const size_t value_size = ap.value_size(); + delegated_ra_memory > mem(num_addresses, value_size, primary_input.as_memory_contents()); + + const size_t type = 0; + + const size_t timestamp = 0; + + const bit_vector root_initial = mem.get_root(); + const size_t pc_addr_initial = ap.initial_pc_addr(); + const bit_vector cpu_state_initial(ap.cpu_state_size(), false); + + const bit_vector root = root_initial; + const size_t pc_addr = pc_addr_initial; + const bit_vector cpu_state = cpu_state_initial; + + const bool has_accepted = false; + + std::shared_ptr > result; + result.reset(new ram_pcd_message(type, ap, timestamp, root_initial, root, pc_addr, cpu_state, pc_addr_initial, cpu_state_initial, has_accepted)); + leave_block("Call to ram_compliance_predicate_handler::get_base_case_message"); + return result; +} + +template +std::shared_ptr > > ram_compliance_predicate_handler::get_final_case_msg(const ram_architecture_params &ap, + const ram_boot_trace &primary_input, + const size_t time_bound) +{ + enter_block("Call to ram_compliance_predicate_handler::get_final_case_msg"); + const size_t num_addresses = 1ul << ap.address_size(); + const size_t value_size = ap.value_size(); + delegated_ra_memory > mem(num_addresses, value_size, primary_input.as_memory_contents()); + + const size_t type = 1; + + const size_t timestamp = time_bound; + + const bit_vector root_initial = mem.get_root(); + const size_t pc_addr_initial = ap.initial_pc_addr(); + const bit_vector cpu_state_initial(ap.cpu_state_size(), false); + + const bit_vector root(root_initial.size(), false); + const size_t pc_addr = 0; + const bit_vector cpu_state = cpu_state_initial; + + const bool has_accepted = true; + + std::shared_ptr > result; + result.reset(new ram_pcd_message(type, ap, timestamp, root_initial, root, pc_addr, cpu_state, pc_addr_initial, cpu_state_initial, has_accepted)); + leave_block("Call to ram_compliance_predicate_handler::get_final_case_msg"); + + return result; +} + +} // libsnark + +#endif // RAM_COMPLIANCE_PREDICATE_TCC_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/zksnark/ram_zksnark/ram_zksnark.hpp b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/zksnark/ram_zksnark/ram_zksnark.hpp new file mode 100644 index 0000000..27eddb4 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/zksnark/ram_zksnark/ram_zksnark.hpp @@ -0,0 +1,224 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for a zkSNARK for RAM. + + This includes: + - the class for a proving key; + - the class for a verification key; + - the class for a key pair (proving key & verification key); + - the class for a proof; + - the generator algorithm; + - the prover algorithm; + - the verifier algorithm. + + The implementation follows, extends, and optimizes the approach described + in \[BCTV14]. Thus, the zkSNARK is constructed from a ppzkPCD for R1CS. + + + Acronyms: + + "R1CS" = "Rank-1 Constraint Systems" + "RAM" = "Random-Access Machines" + "zkSNARK" = "Zero-Knowledge Succinct Non-interactive ARgument of Knowledge" + "ppzkPCD" = "Pre-Processing Zero-Knowledge Proof-Carrying Data" + + References: + + \[BCTV14]: + "Scalable Zero Knowledge via Cycles of Elliptic Curves", + Eli Ben-Sasson, Alessandro Chiesa, Eran Tromer, Madars Virza, + CRYPTO 2014, + + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef RAM_ZKSNARK_HPP_ +#define RAM_ZKSNARK_HPP_ + +#include + +#include "zk_proof_systems/pcd/r1cs_pcd/r1cs_sp_ppzkpcd/r1cs_sp_ppzkpcd.hpp" +#include "zk_proof_systems/zksnark/ram_zksnark/ram_compliance_predicate.hpp" +#include "zk_proof_systems/zksnark/ram_zksnark/ram_zksnark_params.hpp" + +namespace libsnark { + +/******************************** Proving key ********************************/ + +template +class ram_zksnark_proving_key; + +template +std::ostream& operator<<(std::ostream &out, const ram_zksnark_proving_key &pk); + +template +std::istream& operator>>(std::istream &in, ram_zksnark_proving_key &pk); + +/** + * A proving key for the RAM zkSNARK. + */ +template +class ram_zksnark_proving_key { +public: + ram_zksnark_architecture_params ap; + r1cs_sp_ppzkpcd_proving_key > pcd_pk; + + ram_zksnark_proving_key() {} + ram_zksnark_proving_key(const ram_zksnark_proving_key &other) = default; + ram_zksnark_proving_key(ram_zksnark_proving_key &&other) = default; + ram_zksnark_proving_key(const ram_zksnark_architecture_params &ap, + r1cs_sp_ppzkpcd_proving_key > &&pcd_pk) : + ap(ap), + pcd_pk(std::move(pcd_pk)) + {}; + + ram_zksnark_proving_key& operator=(const ram_zksnark_proving_key &other) = default; + + bool operator==(const ram_zksnark_proving_key &other) const; + friend std::ostream& operator<< (std::ostream &out, const ram_zksnark_proving_key &pk); + friend std::istream& operator>> (std::istream &in, ram_zksnark_proving_key &pk); +}; + + +/******************************* Verification key ****************************/ + +template +class ram_zksnark_verification_key; + +template +std::ostream& operator<<(std::ostream &out, const ram_zksnark_verification_key &vk); + +template +std::istream& operator>>(std::istream &in, ram_zksnark_verification_key &vk); + +/** + * A verification key for the RAM zkSNARK. + */ +template +class ram_zksnark_verification_key { +public: + ram_zksnark_architecture_params ap; + r1cs_sp_ppzkpcd_verification_key > pcd_vk; + + ram_zksnark_verification_key() = default; + ram_zksnark_verification_key(const ram_zksnark_verification_key &other) = default; + ram_zksnark_verification_key(ram_zksnark_verification_key &&other) = default; + ram_zksnark_verification_key(const ram_zksnark_architecture_params &ap, + r1cs_sp_ppzkpcd_verification_key > &&pcd_vk) : + ap(ap), + pcd_vk(std::move(pcd_vk)) + {}; + + ram_zksnark_verification_key& operator=(const ram_zksnark_verification_key &other) = default; + + bool operator==(const ram_zksnark_verification_key &other) const; + friend std::ostream& operator<< (std::ostream &out, const ram_zksnark_verification_key &vk); + friend std::istream& operator>> (std::istream &in, ram_zksnark_verification_key &vk); + + static ram_zksnark_verification_key dummy_verification_key(const ram_zksnark_architecture_params &ap); +}; + + +/********************************** Key pair *********************************/ + +/** + * A key pair for the RAM zkSNARK, which consists of a proving key and a verification key. + */ +template +struct ram_zksnark_keypair { +public: + ram_zksnark_proving_key pk; + ram_zksnark_verification_key vk; + + ram_zksnark_keypair() {}; + ram_zksnark_keypair(ram_zksnark_keypair &&other) = default; + ram_zksnark_keypair(ram_zksnark_proving_key &&pk, + ram_zksnark_verification_key &&vk) : + pk(std::move(pk)), + vk(std::move(vk)) + {}; +}; + + +/*********************************** Proof ***********************************/ + +template +class ram_zksnark_proof; + +template +std::ostream& operator<<(std::ostream &out, const ram_zksnark_proof &proof); + +template +std::istream& operator>>(std::istream &in, ram_zksnark_proof &proof); + +/** + * A proof for the RAM zkSNARK. + */ +template +class ram_zksnark_proof { +public: + r1cs_sp_ppzkpcd_proof > PCD_proof; + + ram_zksnark_proof() = default; + ram_zksnark_proof(r1cs_sp_ppzkpcd_proof > &&PCD_proof) : + PCD_proof(std::move(PCD_proof)) {}; + ram_zksnark_proof(const r1cs_sp_ppzkpcd_proof > &PCD_proof) : + PCD_proof(PCD_proof) {}; + + size_t size_in_bits() const + { + return PCD_proof.size_in_bits(); + } + + bool operator==(const ram_zksnark_proof &other) const; + friend std::ostream& operator<< (std::ostream &out, const ram_zksnark_proof &proof); + friend std::istream& operator>> (std::istream &in, ram_zksnark_proof &proof); +}; + + +/***************************** Main algorithms *******************************/ + +/** + * A generator algorithm for the RAM zkSNARK. + * + * Given a choice of architecture parameters, this algorithm produces proving + * and verification keys for all computations that respect this choice. + */ +template +ram_zksnark_keypair ram_zksnark_generator(const ram_zksnark_architecture_params &ap); + +/** + * A prover algorithm for the RAM zkSNARK. + * + * Given a proving key, primary input X, time bound T, and auxiliary input Y, this algorithm + * produces a proof (of knowledge) that attests to the following statement: + * ``there exists Y such that X(Y) accepts within T steps''. + */ +template +ram_zksnark_proof ram_zksnark_prover(const ram_zksnark_proving_key &pk, + const ram_zksnark_primary_input &primary_input, + const size_t time_bound, + const ram_zksnark_auxiliary_input &auxiliary_input); + +/** + * A verifier algorithm for the RAM zkSNARK. + * + * This algorithm is universal in the sense that the verification key + * supports proof verification for *any* choice of primary input and time bound. + */ +template +bool ram_zksnark_verifier(const ram_zksnark_verification_key &vk, + const ram_zksnark_primary_input &primary_input, + const size_t time_bound, + const ram_zksnark_proof &proof); + +} // libsnark + +#include "zk_proof_systems/zksnark/ram_zksnark/ram_zksnark.tcc" + +#endif // RAM_ZKSNARK_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/zksnark/ram_zksnark/ram_zksnark.tcc b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/zksnark/ram_zksnark/ram_zksnark.tcc new file mode 100644 index 0000000..dbdf954 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/zksnark/ram_zksnark/ram_zksnark.tcc @@ -0,0 +1,230 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for a zkSNARK for RAM. + + See ram_zksnark.hpp . + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef RAM_ZKSNARK_TCC_ +#define RAM_ZKSNARK_TCC_ + +#include "common/profiling.hpp" + +namespace libsnark { + +template +bool ram_zksnark_proving_key::operator==(const ram_zksnark_proving_key &other) const +{ + return (this->ap == other.ap && + this->pcd_pk == other.pcd_pk); +} + +template +std::ostream& operator<<(std::ostream &out, const ram_zksnark_proving_key &pk) +{ + out << pk.ap; + out << pk.pcd_pk; + + return out; +} + +template +std::istream& operator>>(std::istream &in, ram_zksnark_proving_key &pk) +{ + in >> pk.ap; + in >> pk.pcd_pk; + + return in; +} + +template +bool ram_zksnark_verification_key::operator==(const ram_zksnark_verification_key &other) const +{ + return (this->ap == other.ap && + this->pcd_vk == other.pcd_vk); +} + +template +std::ostream& operator<<(std::ostream &out, const ram_zksnark_verification_key &vk) +{ + out << vk.ap; + out << vk.pcd_vk; + + return out; +} + +template +std::istream& operator>>(std::istream &in, ram_zksnark_verification_key &vk) +{ + in >> vk.ap; + in >> vk.pcd_vk; + + return in; +} + +template +bool ram_zksnark_proof::operator==(const ram_zksnark_proof &other) const +{ + return (this->PCD_proof == other.PCD_proof); +} + +template +std::ostream& operator<<(std::ostream &out, const ram_zksnark_proof &proof) +{ + out << proof.PCD_proof; + return out; +} + +template +std::istream& operator>>(std::istream &in, ram_zksnark_proof &proof) +{ + in >> proof.PCD_proof; + return in; +} + +template +ram_zksnark_verification_key ram_zksnark_verification_key::dummy_verification_key(const ram_zksnark_architecture_params &ap) +{ + typedef ram_zksnark_PCD_pp pcdT; + + return ram_zksnark_verification_key(ap, r1cs_sp_ppzkpcd_verification_key::dummy_verification_key()); +} + +template +ram_zksnark_keypair ram_zksnark_generator(const ram_zksnark_architecture_params &ap) +{ + typedef ram_zksnark_machine_pp ramT; + typedef ram_zksnark_PCD_pp pcdT; + enter_block("Call to ram_zksnark_generator"); + + enter_block("Generate compliance predicate for RAM"); + ram_compliance_predicate_handler cp_handler(ap); + cp_handler.generate_r1cs_constraints(); + r1cs_sp_ppzkpcd_compliance_predicate ram_compliance_predicate = cp_handler.get_compliance_predicate(); + leave_block("Generate compliance predicate for RAM"); + + enter_block("Generate PCD key pair"); + r1cs_sp_ppzkpcd_keypair kp = r1cs_sp_ppzkpcd_generator(ram_compliance_predicate); + leave_block("Generate PCD key pair"); + + leave_block("Call to ram_zksnark_generator"); + + ram_zksnark_proving_key pk = ram_zksnark_proving_key(ap, std::move(kp.pk)); + ram_zksnark_verification_key vk = ram_zksnark_verification_key(ap, std::move(kp.vk)); + + return ram_zksnark_keypair(std::move(pk), std::move(vk)); +} + +template +ram_zksnark_proof ram_zksnark_prover(const ram_zksnark_proving_key &pk, + const ram_zksnark_primary_input &primary_input, + const size_t time_bound, + const ram_zksnark_auxiliary_input &auxiliary_input) +{ + typedef ram_zksnark_machine_pp ramT; + typedef ram_zksnark_PCD_pp pcdT; + typedef Fr FieldT; // XXX + + assert(log2(time_bound) <= ramT::timestamp_length); + + enter_block("Call to ram_zksnark_prover"); + enter_block("Generate compliance predicate for RAM"); + ram_compliance_predicate_handler cp_handler(pk.ap); + leave_block("Generate compliance predicate for RAM"); + + enter_block("Initialize the RAM computation"); + r1cs_sp_ppzkpcd_proof cur_proof; // start out with an empty proof + + /* initialize memory with the correct values */ + const size_t num_addresses = 1ul << pk.ap.address_size(); + const size_t value_size = pk.ap.value_size(); + + delegated_ra_memory > mem(num_addresses, value_size, primary_input.as_memory_contents()); + std::shared_ptr > msg = ram_compliance_predicate_handler::get_base_case_message(pk.ap, primary_input); + + typename ram_input_tape::const_iterator aux_it = auxiliary_input.begin(); + leave_block("Initialize the RAM computation"); + + enter_block("Execute and prove the computation"); + bool want_halt = false; + for (size_t step = 1; step <= time_bound; ++step) + { + enter_block(FORMAT("", "Prove step %zu out of %zu", step, time_bound)); + + enter_block("Execute witness map"); + + std::shared_ptr > local_data; + local_data.reset(new ram_pcd_local_data(want_halt, mem, aux_it, auxiliary_input.end())); + + cp_handler.generate_r1cs_witness({ msg }, local_data); + + const r1cs_pcd_compliance_predicate_primary_input cp_primary_input(cp_handler.get_outgoing_message()); + const r1cs_pcd_compliance_predicate_auxiliary_input cp_auxiliary_input({ msg }, local_data, cp_handler.get_witness()); + +#ifdef DEBUG + printf("Current state:\n"); + msg->print(); +#endif + + msg = cp_handler.get_outgoing_message(); + +#ifdef DEBUG + printf("Next state:\n"); + msg->print(); +#endif + leave_block("Execute witness map"); + + cur_proof = r1cs_sp_ppzkpcd_prover(pk.pcd_pk, cp_primary_input, cp_auxiliary_input, { cur_proof }); + leave_block(FORMAT("", "Prove step %zu out of %zu", step, time_bound)); + } + leave_block("Execute and prove the computation"); + + enter_block("Finalize the computation"); + want_halt = true; + + enter_block("Execute witness map"); + + std::shared_ptr > local_data; + local_data.reset(new ram_pcd_local_data(want_halt, mem, aux_it, auxiliary_input.end())); + + cp_handler.generate_r1cs_witness({ msg }, local_data); + + const r1cs_pcd_compliance_predicate_primary_input cp_primary_input(cp_handler.get_outgoing_message()); + const r1cs_pcd_compliance_predicate_auxiliary_input cp_auxiliary_input({ msg }, local_data, cp_handler.get_witness()); + leave_block("Execute witness map"); + + cur_proof = r1cs_sp_ppzkpcd_prover(pk.pcd_pk, cp_primary_input, cp_auxiliary_input, { cur_proof }); + leave_block("Finalize the computation"); + + leave_block("Call to ram_zksnark_prover"); + + return cur_proof; +} + +template +bool ram_zksnark_verifier(const ram_zksnark_verification_key &vk, + const ram_zksnark_primary_input &primary_input, + const size_t time_bound, + const ram_zksnark_proof &proof) +{ + typedef ram_zksnark_machine_pp ramT; + typedef ram_zksnark_PCD_pp pcdT; + typedef Fr FieldT; // XXX + + enter_block("Call to ram_zksnark_verifier"); + const r1cs_pcd_compliance_predicate_primary_input cp_primary_input(ram_compliance_predicate_handler::get_final_case_msg(vk.ap, primary_input, time_bound)); + bool ans = r1cs_sp_ppzkpcd_verifier(vk.pcd_vk, cp_primary_input, proof.PCD_proof); + leave_block("Call to ram_zksnark_verifier"); + + return ans; +} + +} // libsnark + +#endif // RAM_ZKSNARK_TCC_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/zksnark/ram_zksnark/ram_zksnark_params.hpp b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/zksnark/ram_zksnark/ram_zksnark_params.hpp new file mode 100644 index 0000000..8f802c6 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/zksnark/ram_zksnark/ram_zksnark_params.hpp @@ -0,0 +1,73 @@ +/** @file + ***************************************************************************** + + Declaration of public-parameter selector for the RAM zkSNARK. + + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef RAM_ZKSNARK_PARAMS_HPP_ +#define RAM_ZKSNARK_PARAMS_HPP_ + +namespace libsnark { + +/** + * The interfaces of the RAM zkSNARK are templatized via the parameter + * ram_zksnark_ppT. When used, the interfaces must be invoked with + * a particular parameter choice; let 'my_ram_zksnark_pp' denote this choice. + * + * The class my_ram_zksnark_pp must contain typedefs for the typenames + * - PCD_pp, and + * - machine_pp. + * + * As well as a method with type signature: + * static void init_public_params() + * + * For example, if you want to use the types my_PCD_pp and my_machine_pp, + * then you would declare my_ram_zksnark_pp as follows: + * + * class my_ram_zksnark_pp { + * public: + * typedef my_PCD_pp PCD_pp; + * typedef my_machine_pp machine_pp; + * static void init_public_params() + * { + * PCD_pp::init_public_params(); // plus other necessary initialization + * } + * }; + * + * Having done the above, my_ram_zksnark_pp can be used as a template parameter. + * + * See default_tinyram_zksnark_pp in the file + * + * common/default_types/tinyram_zksnark_pp.hpp + * + * for an example of the above steps for the case of "RAM=TinyRAM". + * + */ + +/* + * Below are various template aliases (used for convenience). + */ + +template +using ram_zksnark_PCD_pp = typename ram_zksnark_ppT::PCD_pp; + +template +using ram_zksnark_machine_pp = typename ram_zksnark_ppT::machine_pp; + +template +using ram_zksnark_architecture_params = ram_architecture_params >; + +template +using ram_zksnark_primary_input = ram_boot_trace >; + +template +using ram_zksnark_auxiliary_input = ram_input_tape >; + +} // libsnark + +#endif // RAM_ZKSNARK_PARAMS_HPP_ diff --git a/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/zksnark/ram_zksnark/tests/test_ram_zksnark.cpp b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/zksnark/ram_zksnark/tests/test_ram_zksnark.cpp new file mode 100644 index 0000000..70c4193 --- /dev/null +++ b/privacy/zsl/zsl/snark/libsnark/src/zk_proof_systems/zksnark/ram_zksnark/tests/test_ram_zksnark.cpp @@ -0,0 +1,41 @@ +/** + ***************************************************************************** + * @author This file is part of libsnark, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ +#include +#include "common/default_types/ram_zksnark_pp.hpp" +#include "relations/ram_computations/rams/tinyram/tinyram_params.hpp" +#include "zk_proof_systems/zksnark/ram_zksnark/examples/run_ram_zksnark.hpp" +#include "relations/ram_computations/rams/examples/ram_examples.hpp" + +using namespace libsnark; + +template +void test_ram_zksnark(const size_t w, + const size_t k, + const size_t boot_trace_size_bound, + const size_t time_bound) +{ + typedef ram_zksnark_machine_pp ramT; + const ram_architecture_params ap(w, k); + const ram_example example = gen_ram_example_complex(ap, boot_trace_size_bound, time_bound, true); + const bool test_serialization = true; + const bool ans = run_ram_zksnark(example, test_serialization); + assert(ans); +} + +int main(void) +{ + start_profiling(); + ram_zksnark_PCD_pp::init_public_params(); + + const size_t w = 32; + const size_t k = 16; + + const size_t boot_trace_size_bound = 20; + const size_t time_bound = 10; + + test_ram_zksnark(w, k, boot_trace_size_bound, time_bound); +} diff --git a/privacy/zsl/zsl/snark/snark.go b/privacy/zsl/zsl/snark/snark.go new file mode 100644 index 0000000..b800ab8 --- /dev/null +++ b/privacy/zsl/zsl/snark/snark.go @@ -0,0 +1,169 @@ +// Copyright 2017 Zerocoin Electric Coin Company LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package snark + +// #cgo LDFLAGS: -L${SRCDIR} -lzsl -lstdc++ -lgmp -lgomp +// #include +import "C" +import ( + "sync" + "unsafe" +) + +// Init() is only ever called once +var onceInit sync.Once + +func Init() { + onceInit.Do(func() { + C.zsl_initialize() + }) +} + +func ProveTransfer(input_rho_1 [32]byte, + input_sk_1 [32]byte, + input_value_1 uint64, + input_tree_position_1 uint64, + input_authentication_path_1 [29][32]byte, + input_rho_2 [32]byte, + input_sk_2 [32]byte, + input_value_2 uint64, + input_tree_position_2 uint64, + input_authentication_path_2 [29][32]byte, + output_rho_1 [32]byte, + output_pk_1 [32]byte, + output_value_1 uint64, + output_rho_2 [32]byte, + output_pk_2 [32]byte, + output_value_2 uint64) [584]byte { + var proof_buf [584]byte + + C.zsl_prove_transfer(unsafe.Pointer(&proof_buf[0]), + unsafe.Pointer(&input_rho_1[0]), + unsafe.Pointer(&input_sk_1[0]), + C.uint64_t(input_value_1), + C.uint64_t(input_tree_position_1), + unsafe.Pointer(&input_authentication_path_1[0][0]), + unsafe.Pointer(&input_rho_2[0]), + unsafe.Pointer(&input_sk_2[0]), + C.uint64_t(input_value_2), + C.uint64_t(input_tree_position_2), + unsafe.Pointer(&input_authentication_path_2[0][0]), + unsafe.Pointer(&output_rho_1[0]), + unsafe.Pointer(&output_pk_1[0]), + C.uint64_t(output_value_1), + unsafe.Pointer(&output_rho_2[0]), + unsafe.Pointer(&output_pk_2[0]), + C.uint64_t(output_value_2)) + + return proof_buf +} + +func VerifyTransfer(proof [584]byte, + anchor [32]byte, + spend_nf_1 [32]byte, + spend_nf_2 [32]byte, + send_nf_1 [32]byte, + send_nf_2 [32]byte, + cm_1 [32]byte, + cm_2 [32]byte) bool { + ret := C.zsl_verify_transfer(unsafe.Pointer(&proof[0]), + unsafe.Pointer(&anchor[0]), + unsafe.Pointer(&spend_nf_1[0]), + unsafe.Pointer(&spend_nf_2[0]), + unsafe.Pointer(&send_nf_1[0]), + unsafe.Pointer(&send_nf_2[0]), + unsafe.Pointer(&cm_1[0]), + unsafe.Pointer(&cm_2[0])) + + if ret { + return true + } else { + return false + } +} + +func ProveShielding(rho [32]byte, pk [32]byte, value uint64) [584]byte { + var proof_buf [584]byte + + rho_ptr := C.CBytes(rho[:]) + pk_ptr := C.CBytes(pk[:]) + + C.zsl_prove_shielding(rho_ptr, pk_ptr, C.uint64_t(value), unsafe.Pointer(&proof_buf[0])) + + C.free(rho_ptr) + C.free(pk_ptr) + + return proof_buf +} + +func VerifyShielding(proof [584]byte, send_nf [32]byte, cm [32]byte, value uint64) bool { + send_nf_ptr := C.CBytes(send_nf[:]) + cm_ptr := C.CBytes(cm[:]) + ret := C.zsl_verify_shielding(unsafe.Pointer(&proof[0]), send_nf_ptr, cm_ptr, C.uint64_t(value)) + + C.free(send_nf_ptr) + C.free(cm_ptr) + + if ret { + return true + } else { + return false + } +} + +func ProveUnshielding(rho [32]byte, + sk [32]byte, + value uint64, + tree_position uint64, + authentication_path [29][32]byte) [584]byte { + var proof_buf [584]byte + + C.zsl_prove_unshielding(unsafe.Pointer(&rho[0]), + unsafe.Pointer(&sk[0]), + C.uint64_t(value), + C.uint64_t(tree_position), + unsafe.Pointer(&authentication_path[0][0]), + unsafe.Pointer(&proof_buf[0])) + + return proof_buf +} + +func VerifyUnshielding(proof [584]byte, spend_nf [32]byte, rt [32]byte, value uint64) bool { + ret := C.zsl_verify_unshielding(unsafe.Pointer(&proof[0]), + unsafe.Pointer(&spend_nf[0]), + unsafe.Pointer(&rt[0]), + C.uint64_t(value)) + + if ret { + return true + } else { + return false + } +} + +func CreateParamsShielding() { + C.zsl_initialize() + C.zsl_paramgen_shielding() +} + +func CreateParamsUnshielding() { + C.zsl_initialize() + C.zsl_paramgen_unshielding() +} + +func CreateParamsTransfer() { + C.zsl_initialize() + C.zsl_paramgen_transfer() +} diff --git a/privacy/zsl/zsl/snark/snark_test.go b/privacy/zsl/zsl/snark/snark_test.go new file mode 100644 index 0000000..c3b9062 --- /dev/null +++ b/privacy/zsl/zsl/snark/snark_test.go @@ -0,0 +1,240 @@ +// Copyright 2017 Zerocoin Electric Coin Company LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package snark + +import ( + "fmt" + "testing" +) + +// func TestParamgen(t *testing.T) { +// CreateParamsUnshielding() +// } + +func TestInit(t *testing.T) { + Init() +} + +func assertEqual(t *testing.T, a interface{}, b interface{}, message string) { + if a == b { + return + } + if len(message) == 0 { + message = fmt.Sprintf("%v != %v", a, b) + } + t.Fatal(message) +} + +func TestShielding(t *testing.T) { + Init() + + proof := ProveShielding( + [32]byte{0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac}, + [32]byte{0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb}, + 2378237) + + assertEqual(t, VerifyShielding(proof, + [32]byte{0x35, 0xf7, 0xff, 0x84, 0x5e, 0x47, 0x86, 0xd6, 0x44, 0xc9, 0xc9, 0x05, 0xfe, 0x68, 0xfd, 0x0f, 0x60, 0x2f, 0xea, 0x0b, 0xeb, 0x2c, 0x34, 0x1b, 0xc5, 0xd2, 0xde, 0xfc, 0x17, 0xc3, 0x2e, 0x86}, + [32]byte{0xd6, 0x21, 0x8a, 0x07, 0x71, 0x4d, 0xd9, 0xfa, 0xc9, 0x2b, 0xde, 0xef, 0xd3, 0xf4, 0xc0, 0xd7, 0x69, 0xf4, 0x0f, 0x4b, 0x04, 0x3a, 0xd7, 0xe6, 0x7e, 0x73, 0x75, 0xed, 0xc4, 0x98, 0xe4, 0x5c}, + 2378237), true, "proof was not valid as expected") + + assertEqual(t, VerifyShielding(proof, + [32]byte{0x35, 0xf7, 0xff, 0x84, 0x5e, 0x47, 0x86, 0xd6, 0x44, 0xc9, 0xc9, 0x05, 0xfe, 0x68, 0xfd, 0x0f, 0x60, 0x2f, 0xea, 0x0b, 0xeb, 0x2c, 0x34, 0x1b, 0xc5, 0xd2, 0xde, 0xfc, 0x17, 0xc3, 0x2e, 0x86}, + [32]byte{0xd6, 0x21, 0x8a, 0x07, 0x71, 0x4d, 0xd9, 0xfa, 0xc9, 0x2b, 0xde, 0xef, 0xd3, 0xf4, 0xc0, 0xd7, 0x69, 0xf4, 0x0f, 0x4b, 0x04, 0x3a, 0xd7, 0xe6, 0x7e, 0x73, 0x75, 0xed, 0xc4, 0x98, 0xe4, 0x5c}, + 2378236), false, "proof was not invalid as expected") + + assertEqual(t, VerifyShielding(proof, + [32]byte{0x34, 0xf7, 0xff, 0x84, 0x5e, 0x47, 0x86, 0xd6, 0x44, 0xc9, 0xc9, 0x05, 0xfe, 0x68, 0xfd, 0x0f, 0x60, 0x2f, 0xea, 0x0b, 0xeb, 0x2c, 0x34, 0x1b, 0xc5, 0xd2, 0xde, 0xfc, 0x17, 0xc3, 0x2e, 0x86}, + [32]byte{0xd6, 0x21, 0x8a, 0x07, 0x71, 0x4d, 0xd9, 0xfa, 0xc9, 0x2b, 0xde, 0xef, 0xd3, 0xf4, 0xc0, 0xd7, 0x69, 0xf4, 0x0f, 0x4b, 0x04, 0x3a, 0xd7, 0xe6, 0x7e, 0x73, 0x75, 0xed, 0xc4, 0x98, 0xe4, 0x5c}, + 2378237), false, "proof was not invalid as expected") +} + +func TestUnshielding(t *testing.T) { + Init() + + // generated with python by hand :) + // sk = 0xf0f0f0f00f0f0ffffffffff000000f0f0f0f0f00f0000f0f00f00f0f0f0f00ff + // pk = 0xe8e55f617b4b693083f883f70926dd5673fa434cefa3660828759947e2276348 + // rho = 0xdedeffdddedeffdddedeffdddedeffdddedeffdddedeffdddedeffdddedeffdd + // val = 2378237 = 0xfd49240000000000 + // cm = 0x58e38183982c6f7981e9f3ce0a735fdd4ca2f0cd88db6ee608c2fe1e84142d0d + // spend_nf = 0x45ccb210613318d0d127e9947c2ce6b1b246c5c2dd53489c1f39397843410c1a + // anchor = 0x8610652739ac0c6bb6b5353649bb822b26543f0ebe88f32a489a56843cd04f03 + + proof := ProveUnshielding( + [32]byte{0xde, 0xde, 0xff, 0xdd, 0xde, 0xde, 0xff, 0xdd, 0xde, 0xde, 0xff, 0xdd, 0xde, 0xde, 0xff, 0xdd, 0xde, 0xde, 0xff, 0xdd, 0xde, 0xde, 0xff, 0xdd, 0xde, 0xde, 0xff, 0xdd, 0xde, 0xde, 0xff, 0xdd}, + [32]byte{0xf0, 0xf0, 0xf0, 0xf0, 0x0f, 0x0f, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x00, 0xf0, 0x00, 0x0f, 0x0f, 0x00, 0xf0, 0x0f, 0x0f, 0x0f, 0x0f, 0x00, 0xff}, + 2378237, + 0, + [29][32]byte{ + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}}) + + assertEqual(t, VerifyUnshielding(proof, + [32]byte{0x45, 0xcc, 0xb2, 0x10, 0x61, 0x33, 0x18, 0xd0, 0xd1, 0x27, 0xe9, 0x94, 0x7c, 0x2c, 0xe6, 0xb1, 0xb2, 0x46, 0xc5, 0xc2, 0xdd, 0x53, 0x48, 0x9c, 0x1f, 0x39, 0x39, 0x78, 0x43, 0x41, 0x0c, 0x1a}, + [32]byte{0x86, 0x10, 0x65, 0x27, 0x39, 0xac, 0x0c, 0x6b, 0xb6, 0xb5, 0x35, 0x36, 0x49, 0xbb, 0x82, 0x2b, 0x26, 0x54, 0x3f, 0x0e, 0xbe, 0x88, 0xf3, 0x2a, 0x48, 0x9a, 0x56, 0x84, 0x3c, 0xd0, 0x4f, 0x03}, + 2378237), true, "proof was not valid as expected") + + assertEqual(t, VerifyUnshielding(proof, + [32]byte{0x45, 0xcc, 0xb2, 0x10, 0x61, 0x33, 0x18, 0xd0, 0xd1, 0x27, 0xe9, 0x94, 0x7c, 0x2c, 0xe6, 0xb1, 0xb2, 0x46, 0xc5, 0xc2, 0xdd, 0x53, 0x48, 0x9c, 0x1f, 0x39, 0x39, 0x78, 0x43, 0x41, 0x0c, 0x1a}, + [32]byte{0x86, 0x10, 0x65, 0x27, 0x39, 0xac, 0x0c, 0x6b, 0xb6, 0xb5, 0x35, 0x36, 0x49, 0xbb, 0x82, 0x2b, 0x26, 0x54, 0x3f, 0x0e, 0xbe, 0x88, 0xf3, 0x2a, 0x48, 0x9a, 0x56, 0x84, 0x3c, 0xd0, 0x4f, 0x03}, + 2378236), false, "proof was not invalid as expected") + + assertEqual(t, VerifyUnshielding(proof, + [32]byte{0x44, 0xcc, 0xb2, 0x10, 0x61, 0x33, 0x18, 0xd0, 0xd1, 0x27, 0xe9, 0x94, 0x7c, 0x2c, 0xe6, 0xb1, 0xb2, 0x46, 0xc5, 0xc2, 0xdd, 0x53, 0x48, 0x9c, 0x1f, 0x39, 0x39, 0x78, 0x43, 0x41, 0x0c, 0x1a}, + [32]byte{0x86, 0x10, 0x65, 0x27, 0x39, 0xac, 0x0c, 0x6b, 0xb6, 0xb5, 0x35, 0x36, 0x49, 0xbb, 0x82, 0x2b, 0x26, 0x54, 0x3f, 0x0e, 0xbe, 0x88, 0xf3, 0x2a, 0x48, 0x9a, 0x56, 0x84, 0x3c, 0xd0, 0x4f, 0x03}, + 2378237), false, "proof was not invalid as expected") + + assertEqual(t, VerifyUnshielding(proof, + [32]byte{0x45, 0xcc, 0xb2, 0x10, 0x61, 0x33, 0x18, 0xd0, 0xd1, 0x27, 0xe9, 0x94, 0x7c, 0x2c, 0xe6, 0xb1, 0xb2, 0x46, 0xc5, 0xc2, 0xdd, 0x53, 0x48, 0x9c, 0x1f, 0x39, 0x39, 0x78, 0x43, 0x41, 0x0c, 0x1a}, + [32]byte{0x88, 0x10, 0x65, 0x27, 0x39, 0xac, 0x0c, 0x6b, 0xb6, 0xb5, 0x35, 0x36, 0x49, 0xbb, 0x82, 0x2b, 0x26, 0x54, 0x3f, 0x0e, 0xbe, 0x88, 0xf3, 0x2a, 0x48, 0x9a, 0x56, 0x84, 0x3c, 0xd0, 0x4f, 0x03}, + 2378237), false, "proof was not invalid as expected") +} + +func TestTransfer(t *testing.T) { + Init() + + // generated with python by hand :) + // sk = 0xf0f0f0f00f0f0ffffffffff000000f0f0f0f0f00f0000f0f00f00f0f0f0f00ff + // pk = 0xe8e55f617b4b693083f883f70926dd5673fa434cefa3660828759947e2276348 + // rho = 0xdedeffdddedeffdddedeffdddedeffdddedeffdddedeffdddedeffdddedeffdd + // val = 2378237 = 0xfd49240000000000 + // cm = 0x58e38183982c6f7981e9f3ce0a735fdd4ca2f0cd88db6ee608c2fe1e84142d0d + // spend_nf = 0x45ccb210613318d0d127e9947c2ce6b1b246c5c2dd53489c1f39397843410c1a + // anchor = 0x8610652739ac0c6bb6b5353649bb822b26543f0ebe88f32a489a56843cd04f03 + + proof := ProveTransfer( + [32]byte{0xde, 0xde, 0xff, 0xdd, 0xde, 0xde, 0xff, 0xdd, 0xde, 0xde, 0xff, 0xdd, 0xde, 0xde, 0xff, 0xdd, 0xde, 0xde, 0xff, 0xdd, 0xde, 0xde, 0xff, 0xdd, 0xde, 0xde, 0xff, 0xdd, 0xde, 0xde, 0xff, 0xdd}, + [32]byte{0xf0, 0xf0, 0xf0, 0xf0, 0x0f, 0x0f, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x00, 0xf0, 0x00, 0x0f, 0x0f, 0x00, 0xf0, 0x0f, 0x0f, 0x0f, 0x0f, 0x00, 0xff}, + 2378237, + 0, + [29][32]byte{ + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}}, + [32]byte{0xde, 0xde, 0xff, 0xdd, 0xde, 0xde, 0xff, 0xdd, 0xde, 0xde, 0xff, 0xdd, 0xde, 0xde, 0xff, 0xdd, 0xde, 0xde, 0xff, 0xdd, 0xde, 0xde, 0xff, 0xdd, 0xde, 0xde, 0xff, 0xdd, 0xde, 0xde, 0xff, 0xdd}, + [32]byte{0xf0, 0xf0, 0xf0, 0xf0, 0x0f, 0x0f, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x00, 0xf0, 0x00, 0x0f, 0x0f, 0x00, 0xf0, 0x0f, 0x0f, 0x0f, 0x0f, 0x00, 0xff}, + 2378237, + 0, + [29][32]byte{ + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}, + {0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x01, 0x00}}, + [32]byte{0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac}, + [32]byte{0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb}, + 2378237, + [32]byte{0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac}, + [32]byte{0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb, 0xac, 0xfb}, + 2378237) + + assertEqual(t, VerifyTransfer(proof, + [32]byte{0x86, 0x10, 0x65, 0x27, 0x39, 0xac, 0x0c, 0x6b, 0xb6, 0xb5, 0x35, 0x36, 0x49, 0xbb, 0x82, 0x2b, 0x26, 0x54, 0x3f, 0x0e, 0xbe, 0x88, 0xf3, 0x2a, 0x48, 0x9a, 0x56, 0x84, 0x3c, 0xd0, 0x4f, 0x03}, + [32]byte{0x45, 0xcc, 0xb2, 0x10, 0x61, 0x33, 0x18, 0xd0, 0xd1, 0x27, 0xe9, 0x94, 0x7c, 0x2c, 0xe6, 0xb1, 0xb2, 0x46, 0xc5, 0xc2, 0xdd, 0x53, 0x48, 0x9c, 0x1f, 0x39, 0x39, 0x78, 0x43, 0x41, 0x0c, 0x1a}, + [32]byte{0x45, 0xcc, 0xb2, 0x10, 0x61, 0x33, 0x18, 0xd0, 0xd1, 0x27, 0xe9, 0x94, 0x7c, 0x2c, 0xe6, 0xb1, 0xb2, 0x46, 0xc5, 0xc2, 0xdd, 0x53, 0x48, 0x9c, 0x1f, 0x39, 0x39, 0x78, 0x43, 0x41, 0x0c, 0x1a}, + [32]byte{0x35, 0xf7, 0xff, 0x84, 0x5e, 0x47, 0x86, 0xd6, 0x44, 0xc9, 0xc9, 0x05, 0xfe, 0x68, 0xfd, 0x0f, 0x60, 0x2f, 0xea, 0x0b, 0xeb, 0x2c, 0x34, 0x1b, 0xc5, 0xd2, 0xde, 0xfc, 0x17, 0xc3, 0x2e, 0x86}, + [32]byte{0x35, 0xf7, 0xff, 0x84, 0x5e, 0x47, 0x86, 0xd6, 0x44, 0xc9, 0xc9, 0x05, 0xfe, 0x68, 0xfd, 0x0f, 0x60, 0x2f, 0xea, 0x0b, 0xeb, 0x2c, 0x34, 0x1b, 0xc5, 0xd2, 0xde, 0xfc, 0x17, 0xc3, 0x2e, 0x86}, + [32]byte{0xd6, 0x21, 0x8a, 0x07, 0x71, 0x4d, 0xd9, 0xfa, 0xc9, 0x2b, 0xde, 0xef, 0xd3, 0xf4, 0xc0, 0xd7, 0x69, 0xf4, 0x0f, 0x4b, 0x04, 0x3a, 0xd7, 0xe6, 0x7e, 0x73, 0x75, 0xed, 0xc4, 0x98, 0xe4, 0x5c}, + [32]byte{0xd6, 0x21, 0x8a, 0x07, 0x71, 0x4d, 0xd9, 0xfa, 0xc9, 0x2b, 0xde, 0xef, 0xd3, 0xf4, 0xc0, 0xd7, 0x69, 0xf4, 0x0f, 0x4b, 0x04, 0x3a, 0xd7, 0xe6, 0x7e, 0x73, 0x75, 0xed, 0xc4, 0x98, 0xe4, 0x5c}), + true, "proof was not valid as expected") + + assertEqual(t, VerifyTransfer(proof, + [32]byte{0x85, 0x10, 0x65, 0x27, 0x39, 0xac, 0x0c, 0x6b, 0xb6, 0xb5, 0x35, 0x36, 0x49, 0xbb, 0x82, 0x2b, 0x26, 0x54, 0x3f, 0x0e, 0xbe, 0x88, 0xf3, 0x2a, 0x48, 0x9a, 0x56, 0x84, 0x3c, 0xd0, 0x4f, 0x03}, + [32]byte{0x45, 0xcc, 0xb2, 0x10, 0x61, 0x33, 0x18, 0xd0, 0xd1, 0x27, 0xe9, 0x94, 0x7c, 0x2c, 0xe6, 0xb1, 0xb2, 0x46, 0xc5, 0xc2, 0xdd, 0x53, 0x48, 0x9c, 0x1f, 0x39, 0x39, 0x78, 0x43, 0x41, 0x0c, 0x1a}, + [32]byte{0x45, 0xcc, 0xb2, 0x10, 0x61, 0x33, 0x18, 0xd0, 0xd1, 0x27, 0xe9, 0x94, 0x7c, 0x2c, 0xe6, 0xb1, 0xb2, 0x46, 0xc5, 0xc2, 0xdd, 0x53, 0x48, 0x9c, 0x1f, 0x39, 0x39, 0x78, 0x43, 0x41, 0x0c, 0x1a}, + [32]byte{0x35, 0xf7, 0xff, 0x84, 0x5e, 0x47, 0x86, 0xd6, 0x44, 0xc9, 0xc9, 0x05, 0xfe, 0x68, 0xfd, 0x0f, 0x60, 0x2f, 0xea, 0x0b, 0xeb, 0x2c, 0x34, 0x1b, 0xc5, 0xd2, 0xde, 0xfc, 0x17, 0xc3, 0x2e, 0x86}, + [32]byte{0x35, 0xf7, 0xff, 0x84, 0x5e, 0x47, 0x86, 0xd6, 0x44, 0xc9, 0xc9, 0x05, 0xfe, 0x68, 0xfd, 0x0f, 0x60, 0x2f, 0xea, 0x0b, 0xeb, 0x2c, 0x34, 0x1b, 0xc5, 0xd2, 0xde, 0xfc, 0x17, 0xc3, 0x2e, 0x86}, + [32]byte{0xd6, 0x21, 0x8a, 0x07, 0x71, 0x4d, 0xd9, 0xfa, 0xc9, 0x2b, 0xde, 0xef, 0xd3, 0xf4, 0xc0, 0xd7, 0x69, 0xf4, 0x0f, 0x4b, 0x04, 0x3a, 0xd7, 0xe6, 0x7e, 0x73, 0x75, 0xed, 0xc4, 0x98, 0xe4, 0x5c}, + [32]byte{0xd6, 0x21, 0x8a, 0x07, 0x71, 0x4d, 0xd9, 0xfa, 0xc9, 0x2b, 0xde, 0xef, 0xd3, 0xf4, 0xc0, 0xd7, 0x69, 0xf4, 0x0f, 0x4b, 0x04, 0x3a, 0xd7, 0xe6, 0x7e, 0x73, 0x75, 0xed, 0xc4, 0x98, 0xe4, 0x5c}), + false, "proof was not invalid as expected") +} diff --git a/privacy/zsl/zsl/snark/zsl.h b/privacy/zsl/zsl/snark/zsl.h new file mode 100644 index 0000000..bb53c6d --- /dev/null +++ b/privacy/zsl/zsl/snark/zsl.h @@ -0,0 +1,112 @@ +// Copyright 2017 Zerocoin Electric Coin Company LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef _ZSL_H_ +#define _ZSL_H_ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + + void zsl_initialize(); + bool zsl_verify_shielding( + void *proof, + void *send_nf, + void *cm, + uint64_t value + ); + void zsl_prove_shielding( + void *rho, + void *pk, + uint64_t value, + void *output_proof + ); + void zsl_paramgen_shielding(); + + void zsl_prove_unshielding( + void *rho, + void *sk, + uint64_t value, + uint64_t tree_position, + void *authentication_path, + void *output_proof + ); + bool zsl_verify_unshielding( + void *proof_ptr, + void *spend_nf_ptr, + void *rt_ptr, + uint64_t value + ); + + void zsl_paramgen_unshielding(); + + void zsl_paramgen_transfer(); + + void zsl_prove_transfer( + void *output_proof_ptr, + void *input_rho_ptr_1, + void *input_pk_ptr_1, + uint64_t input_value_1, + uint64_t input_tree_position_1, + void *input_authentication_path_ptr_1, + void *input_rho_ptr_2, + void *input_pk_ptr_2, + uint64_t input_value_2, + uint64_t input_tree_position_2, + void *input_authentication_path_ptr_2, + void *output_rho_ptr_1, + void *output_pk_ptr_1, + uint64_t output_value_1, + void *output_rho_ptr_2, + void *output_pk_ptr_2, + uint64_t output_value_2 + ); + + bool zsl_verify_transfer( + void *proof_ptr, + void *anchor_ptr, + void *spend_nf_ptr_1, + void *spend_nf_ptr_2, + void *send_nf_ptr_1, + void *send_nf_ptr_2, + void *cm_ptr_1, + void *cm_ptr_2 + ); + + /* + void get_new_address(void *a_sk, void *a_pk); + void get_randomness(void *hash); + void root(); + void get_proof_from_hex(void *hex, void *proof); + void get_witness(void *witness); + + void compute_send_nullifier(void *rho, void *send_nf); + void compute_spend_nullifier(void *rho, void *sk, void *spend_nf); + void compute_commitment(void *rho, void *pk, uint64_t value, void *cm); + void + + void shield(); + void unshiled(); + void transfer(); + */ + +#ifdef __cplusplus +} +#endif + +#endif